home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / public / ImageMagick / magick / widget.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-02  |  197.8 KB  |  6,268 lines

  1. /*
  2. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  3. %                                                                             %
  4. %                                                                             %
  5. %                                                                             %
  6. %                                                                             %
  7. %                  W   W  IIIII  DDDD    GGGG  EEEEE  TTTTT                   %
  8. %                  W   W    I    D   D  G      E        T                     %
  9. %                  W W W    I    D   D  G  GG  EEE      T                     %
  10. %                  WW WW    I    D   D  G   G  E        T                     %
  11. %                  W   W  IIIII  DDDD    GGGG  EEEEE    T                     %
  12. %                                                                             %
  13. %                X11 User Interface Routines for ImageMagick.                 %
  14. %                                                                             %
  15. %                                                                             %
  16. %                              Software Design                                %
  17. %                                John Cristy                                  %
  18. %                              September 1993                                 %
  19. %                                                                             %
  20. %                                                                             %
  21. %  Copyright 1994 E. I. du Pont de Nemours & Company                          %
  22. %                                                                             %
  23. %  Permission to use, copy, modify, distribute, and sell this software and    %
  24. %  its documentation for any purpose is hereby granted without fee,           %
  25. %  provided that the above Copyright notice appear in all copies and that     %
  26. %  both that Copyright notice and this permission notice appear in            %
  27. %  supporting documentation, and that the name of E. I. du Pont de Nemours    %
  28. %  & Company not be used in advertising or publicity pertaining to            %
  29. %  distribution of the software without specific, written prior               %
  30. %  permission.  E. I. du Pont de Nemours & Company makes no representations   %
  31. %  about the suitability of this software for any purpose.  It is provided    %
  32. %  "as is" without express or implied warranty.                               %
  33. %                                                                             %
  34. %  E. I. du Pont de Nemours & Company disclaims all warranties with regard    %
  35. %  to this software, including all implied warranties of merchantability      %
  36. %  and fitness, in no event shall E. I. du Pont de Nemours & Company be       %
  37. %  liable for any special, indirect or consequential damages or any           %
  38. %  damages whatsoever resulting from loss of use, data or profits, whether    %
  39. %  in an action of contract, negligence or other tortuous action, arising     %
  40. %  out of or in connection with the use or performance of this software.      %
  41. %                                                                             %
  42. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  43. %
  44. %
  45. */
  46.  
  47. /*
  48.   Include declarations.
  49. */
  50. #include "magick.h"
  51. #include "image.h"
  52. #include "utility.h"
  53. #include "X.h"
  54. #include "widget.h"
  55.  
  56. /*
  57.   Define declarations.
  58. */
  59. #define MatteIsActive(matte_info,position)  \
  60.   ((position.x >= (matte_info.x-matte_info.bevel_width)) && \
  61.    (position.y >= (matte_info.y-matte_info.bevel_width)) &&  \
  62.    (position.x < (matte_info.x+matte_info.width+matte_info.bevel_width)) &&  \
  63.    (position.y < (matte_info.y+matte_info.height+matte_info.bevel_width)))
  64. /*
  65.   State declarations.
  66. */
  67. #define ControlState  0x0001
  68. #define DefaultState  0x0000
  69. #define ExitState  0x0002
  70. #define RedrawActionState  0x0004
  71. #define RedrawListState  0x0008
  72. #define RedrawWidgetState  0x0010
  73. #define UpdateConfigurationState  0x0020
  74. #define UpdateListState  0x0040
  75.  
  76. /*
  77.   Forward declarations.
  78. */
  79. static void
  80.   XDrawMatte _Declare((Display *,XWindowInfo *,XWidgetInfo *)),
  81.   XSetBevelColor _Declare((Display *,XWindowInfo *,unsigned int)),
  82.   XSetMatteColor _Declare((Display *,XWindowInfo *,unsigned int)),
  83.   XSetTextColor _Declare((Display *,XWindowInfo *,unsigned int));
  84.  
  85. /*
  86. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  87. %                                                                             %
  88. %                                                                             %
  89. %                                                                             %
  90. %   X D r a w B e v e l                                                       %
  91. %                                                                             %
  92. %                                                                             %
  93. %                                                                             %
  94. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  95. %
  96. %  Function XDrawBevel "sets off" an area with a highlighted upper and
  97. %  left bevel and a shadowed lower and right bevel.  The highlighted and
  98. %  shadowed bevels create a 3-D effect.
  99. %
  100. %  The format of the XDrawBevel function is:
  101. %
  102. %      XDrawBevel(display,window_info,bevel_info)
  103. %
  104. %  A description of each parameter follows:
  105. %
  106. %    o display: Specifies a pointer to the Display structure;  returned from
  107. %      XOpenDisplay.
  108. %
  109. %    o window_info: Specifies a pointer to a X11 XWindowInfo structure.
  110. %
  111. %    o bevel_info: Specifies a pointer to a XWidgetInfo structure.  It
  112. %      contains the extents of the bevel.
  113. %
  114. %
  115. */
  116. static void XDrawBevel(display,window_info,bevel_info)
  117. Display
  118.   *display;
  119.  
  120. XWindowInfo
  121.   *window_info;
  122.  
  123. XWidgetInfo
  124.   *bevel_info;
  125. {
  126.   int
  127.     x1,
  128.     x2,
  129.     y1,
  130.     y2;
  131.  
  132.   unsigned int
  133.     bevel_width;
  134.  
  135.   XPoint
  136.     points[6];
  137.  
  138.   /*
  139.     Draw upper and left beveled border.
  140.   */
  141.   x1=bevel_info->x;
  142.   y1=bevel_info->y+bevel_info->height;
  143.   x2=bevel_info->x+bevel_info->width;
  144.   y2=bevel_info->y;
  145.   bevel_width=bevel_info->bevel_width;
  146.   points[0].x=x1;
  147.   points[0].y=y1;
  148.   points[1].x=x1;
  149.   points[1].y=y2;
  150.   points[2].x=x2;
  151.   points[2].y=y2;
  152.   points[3].x=x2+bevel_width;
  153.   points[3].y=y2-bevel_width;
  154.   points[4].x=x1-bevel_width;
  155.   points[4].y=y2-bevel_width;
  156.   points[5].x=x1-bevel_width;
  157.   points[5].y=y1+bevel_width;
  158.   XSetBevelColor(display,window_info,bevel_info->raised);
  159.   XFillPolygon(display,window_info->id,window_info->widget_context,points,6,
  160.     Complex,CoordModeOrigin);
  161.   /*
  162.     Draw lower and right beveled border.
  163.   */
  164.   points[0].x=x1;
  165.   points[0].y=y1;
  166.   points[1].x=x2;
  167.   points[1].y=y1;
  168.   points[2].x=x2;
  169.   points[2].y=y2;
  170.   points[3].x=x2+bevel_width;
  171.   points[3].y=y2-bevel_width;
  172.   points[4].x=x2+bevel_width;
  173.   points[4].y=y1+bevel_width;
  174.   points[5].x=x1-bevel_width;
  175.   points[5].y=y1+bevel_width;
  176.   XSetBevelColor(display,window_info,(unsigned int) !bevel_info->raised);
  177.   XFillPolygon(display,window_info->id,window_info->widget_context,points,6,
  178.     Complex,CoordModeOrigin);
  179.   XSetFillStyle(display,window_info->widget_context,FillSolid);
  180. }
  181.  
  182. /*
  183. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  184. %                                                                             %
  185. %                                                                             %
  186. %                                                                             %
  187. %   X D r a w B e v e l e d B u t t o n                                       %
  188. %                                                                             %
  189. %                                                                             %
  190. %                                                                             %
  191. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  192. %
  193. %  Function XDrawBeveledButton draws a button with a highlighted upper and
  194. %  left bevel and a shadowed lower and right bevel.  The highlighted and
  195. %  shadowed bevels create a 3-D effect.
  196. %
  197. %  The format of the XDrawBeveledButton function is:
  198. %
  199. %      XDrawBeveledButton(display,window_info,button_info)
  200. %
  201. %  A description of each parameter follows:
  202. %
  203. %    o display: Specifies a pointer to the Display structure;  returned from
  204. %      XOpenDisplay.
  205. %
  206. %    o window_info: Specifies a pointer to a X11 XWindowInfo structure.
  207. %
  208. %    o button_info: Specifies a pointer to a XWidgetInfo structure.  It
  209. %      contains the extents of the button.
  210. %
  211. %
  212. */
  213. static void XDrawBeveledButton(display,window_info,button_info)
  214. Display
  215.   *display;
  216.  
  217. XWindowInfo
  218.   *window_info;
  219.  
  220. XWidgetInfo
  221.   *button_info;
  222. {
  223.   int
  224.     x,
  225.     y;
  226.  
  227.   unsigned int
  228.     width;
  229.  
  230.   XFontStruct
  231.     *font_info;
  232.  
  233.   XRectangle
  234.     clip_info;
  235.  
  236.   /*
  237.     Draw matte.
  238.   */
  239.   XDrawBevel(display,window_info,button_info);
  240.   XSetMatteColor(display,window_info,button_info->raised);
  241.   XFillRectangle(display,window_info->id,window_info->widget_context,
  242.     button_info->x,button_info->y,button_info->width,button_info->height);
  243.   XSetTextColor(display,window_info,button_info->raised);
  244.   x=button_info->x-button_info->bevel_width-1;
  245.   y=button_info->y-button_info->bevel_width-1;
  246.   if (button_info->raised || (window_info->depth == 1))
  247.     XDrawRectangle(display,window_info->id,window_info->widget_context,x,y,
  248.       button_info->width+(button_info->bevel_width << 1)+1,button_info->height+
  249.       (button_info->bevel_width << 1)+1);
  250.   if (button_info->text == (char *) NULL)
  251.     return;
  252.   /*
  253.     Set clipping region.
  254.   */
  255.   clip_info.width=button_info->width;
  256.   clip_info.height=button_info->height;
  257.   clip_info.x=button_info->x;
  258.   clip_info.y=button_info->y;
  259.   /*
  260.     Draw text.
  261.   */
  262.   XSetClipRectangles(display,window_info->widget_context,0,0,&clip_info,1,
  263.     Unsorted);
  264.   font_info=window_info->font_info;
  265.   width=XTextWidth(font_info,button_info->text,strlen(button_info->text));
  266.   x=button_info->x+(button_info->width >> 1)-(width >> 1);
  267.   if (x < button_info->x)
  268.     x=button_info->x;
  269.   y=button_info->y+
  270.     ((button_info->height-(font_info->ascent+font_info->descent)) >> 1);
  271.   if (y < button_info->y)
  272.     y=button_info->y;
  273.   y+=window_info->font_info->ascent;
  274.   XDrawString(display,window_info->id,window_info->widget_context,x,y,
  275.     button_info->text,strlen(button_info->text));
  276.   XSetClipMask(display,window_info->widget_context,None);
  277. }
  278.  
  279. /*
  280. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  281. %                                                                             %
  282. %                                                                             %
  283. %                                                                             %
  284. %   X D r a w B e v e l e d M a t t e                                         %
  285. %                                                                             %
  286. %                                                                             %
  287. %                                                                             %
  288. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  289. %
  290. %  Function XDrawBeveledMatte draws a matte with a shadowed upper and
  291. %  left bevel and a highlighted lower and right bevel.  The highlighted and
  292. %  shadowed bevels create a 3-D effect.
  293. %
  294. %  The format of the XDrawBeveledMatte function is:
  295. %
  296. %      XDrawBeveledMatte(display,window_info,matte_info)
  297. %
  298. %  A description of each parameter follows:
  299. %
  300. %    o display: Specifies a pointer to the Display structure;  returned from
  301. %      XOpenDisplay.
  302. %
  303. %    o window_info: Specifies a pointer to a X11 XWindowInfo structure.
  304. %
  305. %    o matte_info: Specifies a pointer to a XWidgetInfo structure.  It
  306. %      contains the extents of the matte.
  307. %
  308. %
  309. */
  310. static void XDrawBeveledMatte(display,window_info,matte_info)
  311. Display
  312.   *display;
  313.  
  314. XWindowInfo
  315.   *window_info;
  316.  
  317. XWidgetInfo
  318.   *matte_info;
  319. {
  320.   /*
  321.     Draw matte.
  322.   */
  323.   XDrawBevel(display,window_info,matte_info);
  324.   XDrawMatte(display,window_info,matte_info);
  325. }
  326.  
  327. /*
  328. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  329. %                                                                             %
  330. %                                                                             %
  331. %                                                                             %
  332. %   X D r a w M a t t e                                                       %
  333. %                                                                             %
  334. %                                                                             %
  335. %                                                                             %
  336. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  337. %
  338. %  Function XDrawMatte fills a rectangular area with the matte color.
  339. %
  340. %  The format of the XDrawMatte function is:
  341. %
  342. %      XDrawMatte(display,window_info,matte_info)
  343. %
  344. %  A description of each parameter follows:
  345. %
  346. %    o display: Specifies a pointer to the Display structure;  returned from
  347. %      XOpenDisplay.
  348. %
  349. %    o window_info: Specifies a pointer to a X11 XWindowInfo structure.
  350. %
  351. %    o matte_info: Specifies a pointer to a XWidgetInfo structure.  It
  352. %      contains the extents of the matte.
  353. %
  354. %
  355. */
  356. static void XDrawMatte(display,window_info,matte_info)
  357. Display
  358.   *display;
  359.  
  360. XWindowInfo
  361.   *window_info;
  362.  
  363. XWidgetInfo
  364.   *matte_info;
  365. {
  366.   /*
  367.     Draw matte.
  368.   */
  369.   if (!matte_info->trough || (window_info->depth == 1))
  370.     XFillRectangle(display,window_info->id,window_info->highlight_context,
  371.       matte_info->x,matte_info->y,matte_info->width,matte_info->height);
  372.   else
  373.     {
  374.       XSetForeground(display,window_info->widget_context,
  375.         window_info->pixel_info->trough_color.pixel);
  376.       XFillRectangle(display,window_info->id,window_info->widget_context,
  377.         matte_info->x,matte_info->y,matte_info->width,matte_info->height);
  378.     }
  379. }
  380.  
  381. /*
  382. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  383. %                                                                             %
  384. %                                                                             %
  385. %                                                                             %
  386. %   X D r a w M a t t e T e x t                                               %
  387. %                                                                             %
  388. %                                                                             %
  389. %                                                                             %
  390. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  391. %
  392. %  Function XDrawMatteText draws a matte with text.  If the text exceeds the
  393. %  extents of the text, a portion of the text relative to the cursor is
  394. %  displayed.
  395. %
  396. %  The format of the XDrawMatteText function is:
  397. %
  398. %      XDrawMatteText(display,window_info,text_info)
  399. %
  400. %  A description of each parameter follows:
  401. %
  402. %    o display: Specifies a pointer to the Display structure;  returned from
  403. %      XOpenDisplay.
  404. %
  405. %    o window_info: Specifies a pointer to a X11 XWindowInfo structure.
  406. %
  407. %    o text_info: Specifies a pointer to a XWidgetInfo structure.  It
  408. %      contains the extents of the text.
  409. %
  410. %
  411. */
  412. static void XDrawMatteText(display,window_info,text_info)
  413. Display
  414.   *display;
  415.  
  416. XWindowInfo
  417.   *window_info;
  418.  
  419. XWidgetInfo
  420.   *text_info;
  421. {
  422.   char
  423.     *text;
  424.  
  425.   GC
  426.     widget_context;
  427.  
  428.   int
  429.     x,
  430.     y;
  431.  
  432.   register int
  433.     i;
  434.  
  435.   unsigned int
  436.     width;
  437.  
  438.   XFontStruct
  439.     *font_info;
  440.  
  441.   /*
  442.     Clear the text area.
  443.   */
  444.   XSetMatteColor(display,window_info,False);
  445.   XFillRectangle(display,window_info->id,window_info->widget_context,
  446.     text_info->x,text_info->y,text_info->width,text_info->height);
  447.   if (text_info->text == (char *) NULL)
  448.     return;
  449.   if (*text_info->text == '\0')
  450.     return;
  451.   /*
  452.     Determine beginning of the visible text.
  453.   */
  454.   font_info=window_info->font_info;
  455.   width=text_info->width-(font_info->max_bounds.width >> 1);
  456.   if (text_info->cursor < text_info->marker)
  457.     text_info->marker=text_info->cursor;
  458.   else
  459.     {
  460.       text=text_info->marker;
  461.       if (XTextWidth(font_info,text,text_info->cursor-text) > width)
  462.         {
  463.           text=text_info->text;
  464.           for (i=0; i < (int) strlen(text); i++)
  465.             if (XTextWidth(font_info,text+i,text_info->cursor-text-i) <= width)
  466.               break;
  467.           text_info->marker=text+i;
  468.         }
  469.     }
  470.   /*
  471.     Determine end of the visible text.
  472.   */
  473.   for (i=0; i < (int) strlen(text_info->marker); i++)
  474.     if (XTextWidth(font_info,text_info->marker,i+1) > width)
  475.       break;
  476.   /*
  477.     Draw text and cursor.
  478.   */
  479.   XSetTextColor(display,window_info,text_info->highlight);
  480.   widget_context=window_info->widget_context;
  481.   if (text_info->highlight)
  482.     widget_context=window_info->highlight_context;
  483.   x=text_info->x+(font_info->max_bounds.width >> 2);
  484.   y=text_info->y+font_info->ascent+(text_info->height >> 2);
  485.   XDrawImageString(display,window_info->id,widget_context,x,y,
  486.     text_info->marker,i);
  487.   x+=
  488.     XTextWidth(font_info,text_info->marker,text_info->cursor-text_info->marker);
  489.   XDrawLine(display,window_info->id,window_info->annotate_context,x,y+3,
  490.     x,y-(font_info->ascent+font_info->descent)+3);
  491. }
  492.  
  493. /*
  494. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  495. %                                                                             %
  496. %                                                                             %
  497. %                                                                             %
  498. %   X D r a w T r i a n g l e N o r t h                                       %
  499. %                                                                             %
  500. %                                                                             %
  501. %                                                                             %
  502. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  503. %
  504. %  Function XDrawTriangleNorth draws a triangle with a highlighted left
  505. %  bevel and a shadowed right and lower bevel.  The highlighted and
  506. %  shadowed bevels create a 3-D effect.
  507. %
  508. %  The format of the XDrawTriangleNorth function is:
  509. %
  510. %      XDrawTriangleNorth(display,window_info,triangle_info)
  511. %
  512. %  A description of each parameter follows:
  513. %
  514. %    o display: Specifies a pointer to the Display structure;  returned from
  515. %      XOpenDisplay.
  516. %
  517. %    o window_info: Specifies a pointer to a X11 XWindowInfo structure.
  518. %
  519. %    o triangle_info: Specifies a pointer to a XWidgetInfo structure.  It
  520. %      contains the extents of the triangle.
  521. %
  522. %
  523. */
  524. static void XDrawTriangleNorth(display,window_info,triangle_info)
  525. Display
  526.   *display;
  527.  
  528. XWindowInfo
  529.   *window_info;
  530.  
  531. XWidgetInfo
  532.   *triangle_info;
  533. {
  534.   int
  535.     x1,
  536.     x2,
  537.     x3,
  538.     y1,
  539.     y2,
  540.     y3;
  541.  
  542.   unsigned int
  543.     bevel_width;
  544.  
  545.   XPoint
  546.     points[4];
  547.  
  548.   /*
  549.     Draw triangle matte.
  550.   */
  551.   x1=triangle_info->x;
  552.   y1=triangle_info->y+triangle_info->height;
  553.   x2=triangle_info->x+(triangle_info->width >> 1);
  554.   y2=triangle_info->y;
  555.   x3=triangle_info->x+triangle_info->width;
  556.   y3=triangle_info->y+triangle_info->height;
  557.   bevel_width=triangle_info->bevel_width;
  558.   points[0].x=x1;
  559.   points[0].y=y1;
  560.   points[1].x=x2;
  561.   points[1].y=y2;
  562.   points[2].x=x3;
  563.   points[2].y=y3;
  564.   XSetMatteColor(display,window_info,triangle_info->raised);
  565.   XFillPolygon(display,window_info->id,window_info->widget_context,points,3,
  566.     Complex,CoordModeOrigin);
  567.   /*
  568.     Draw left bevel.
  569.   */
  570.   points[0].x=x1;
  571.   points[0].y=y1;
  572.   points[1].x=x2;
  573.   points[1].y=y2;
  574.   points[2].x=x2;
  575.   points[2].y=y2-bevel_width-2;
  576.   points[3].x=x1-bevel_width-1;
  577.   points[3].y=y1+bevel_width;
  578.   XSetBevelColor(display,window_info,triangle_info->raised);
  579.   XFillPolygon(display,window_info->id,window_info->widget_context,points,4,
  580.     Complex,CoordModeOrigin);
  581.   /*
  582.     Draw right bevel.
  583.   */
  584.   points[0].x=x2;
  585.   points[0].y=y2;
  586.   points[1].x=x3;
  587.   points[1].y=y3;
  588.   points[2].x=x3+bevel_width;
  589.   points[2].y=y3+bevel_width;
  590.   points[3].x=x2;
  591.   points[3].y=y2-bevel_width;
  592.   XSetBevelColor(display,window_info,(unsigned int) !triangle_info->raised);
  593.   XFillPolygon(display,window_info->id,window_info->widget_context,points,4,
  594.     Complex,CoordModeOrigin);
  595.   /*
  596.     Draw lower bevel.
  597.   */
  598.   points[0].x=x3;
  599.   points[0].y=y3;
  600.   points[1].x=x1;
  601.   points[1].y=y1;
  602.   points[2].x=x1-bevel_width;
  603.   points[2].y=y1+bevel_width;
  604.   points[3].x=x3+bevel_width;
  605.   points[3].y=y3+bevel_width;
  606.   XFillPolygon(display,window_info->id,window_info->widget_context,points,4,
  607.     Complex,CoordModeOrigin);
  608.   XSetFillStyle(display,window_info->widget_context,FillSolid);
  609. }
  610.  
  611. /*
  612. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  613. %                                                                             %
  614. %                                                                             %
  615. %                                                                             %
  616. %   X D r a w T r i a n g l e S o u t h                                       %
  617. %                                                                             %
  618. %                                                                             %
  619. %                                                                             %
  620. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  621. %
  622. %  Function XDrawTriangleSouth draws a border with a highlighted left and
  623. %  right bevel and a shadowed lower bevel.  The highlighted and shadowed
  624. %  bevels create a 3-D effect.
  625. %
  626. %  The format of the XDrawTriangleSouth function is:
  627. %
  628. %      XDrawTriangleSouth(display,window_info,triangle_info)
  629. %
  630. %  A description of each parameter follows:
  631. %
  632. %    o display: Specifies a pointer to the Display structure;  returned from
  633. %      XOpenDisplay.
  634. %
  635. %    o window_info: Specifies a pointer to a X11 XWindowInfo structure.
  636. %
  637. %    o triangle_info: Specifies a pointer to a XWidgetInfo structure.  It
  638. %      contains the extents of the triangle.
  639. %
  640. %
  641. */
  642. static void XDrawTriangleSouth(display,window_info,triangle_info)
  643. Display
  644.   *display;
  645.  
  646. XWindowInfo
  647.   *window_info;
  648.  
  649. XWidgetInfo
  650.   *triangle_info;
  651. {
  652.   int
  653.     x1,
  654.     x2,
  655.     x3,
  656.     y1,
  657.     y2,
  658.     y3;
  659.  
  660.   unsigned int
  661.     bevel_width;
  662.  
  663.   XPoint
  664.     points[4];
  665.  
  666.   /*
  667.     Draw triangle matte.
  668.   */
  669.   x1=triangle_info->x;
  670.   y1=triangle_info->y;
  671.   x2=triangle_info->x+(triangle_info->width >> 1);
  672.   y2=triangle_info->y+triangle_info->height;
  673.   x3=triangle_info->x+triangle_info->width;
  674.   y3=triangle_info->y;
  675.   bevel_width=triangle_info->bevel_width;
  676.   points[0].x=x1;
  677.   points[0].y=y1;
  678.   points[1].x=x2;
  679.   points[1].y=y2;
  680.   points[2].x=x3;
  681.   points[2].y=y3;
  682.   XSetMatteColor(display,window_info,triangle_info->raised);
  683.   XFillPolygon(display,window_info->id,window_info->widget_context,points,3,
  684.     Complex,CoordModeOrigin);
  685.   /*
  686.     Draw top bevel.
  687.   */
  688.   points[0].x=x3;
  689.   points[0].y=y3;
  690.   points[1].x=x1;
  691.   points[1].y=y1;
  692.   points[2].x=x1-bevel_width;
  693.   points[2].y=y1-bevel_width;
  694.   points[3].x=x3+bevel_width;
  695.   points[3].y=y3-bevel_width;
  696.   XSetBevelColor(display,window_info,triangle_info->raised);
  697.   XFillPolygon(display,window_info->id,window_info->widget_context,points,4,
  698.     Complex,CoordModeOrigin);
  699.   /*
  700.     Draw right bevel.
  701.   */
  702.   points[0].x=x2;
  703.   points[0].y=y2;
  704.   points[1].x=x3+1;
  705.   points[1].y=y3-bevel_width;
  706.   points[2].x=x3+bevel_width;
  707.   points[2].y=y3-bevel_width;
  708.   points[3].x=x2;
  709.   points[3].y=y2+bevel_width;
  710.   XSetBevelColor(display,window_info,(unsigned int) !triangle_info->raised);
  711.   XFillPolygon(display,window_info->id,window_info->widget_context,points,4,
  712.     Complex,CoordModeOrigin);
  713.   /*
  714.     Draw left bevel.
  715.   */
  716.   points[0].x=x1;
  717.   points[0].y=y1;
  718.   points[1].x=x2;
  719.   points[1].y=y2;
  720.   points[2].x=x2;
  721.   points[2].y=y2+bevel_width;
  722.   points[3].x=x1-bevel_width;
  723.   points[3].y=y1-bevel_width;
  724.   XSetBevelColor(display,window_info,triangle_info->raised);
  725.   XFillPolygon(display,window_info->id,window_info->widget_context,points,4,
  726.     Complex,CoordModeOrigin);
  727.   XSetFillStyle(display,window_info->widget_context,FillSolid);
  728. }
  729.  
  730. /*
  731. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  732. %                                                                             %
  733. %                                                                             %
  734. %                                                                             %
  735. %   X D r a w W i d g e t T e x t                                             %
  736. %                                                                             %
  737. %                                                                             %
  738. %                                                                             %
  739. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  740. %
  741. %  Function XDrawWidgetText first clears the widget and draws a text string
  742. %  justifed left in the x-direction and centered within the y-direction.
  743. %
  744. %  The format of the XDrawWidgetText function is:
  745. %
  746. %      XDrawWidgetText(display,window_info,text_info)
  747. %
  748. %  A description of each parameter follows:
  749. %
  750. %    o display: Specifies a pointer to the Display structure;  returned from
  751. %      XOpenDisplay.
  752. %
  753. %    o window_info: Specifies a pointer to a XWindowText structure.
  754. %
  755. %    o text_info: Specifies a pointer to XWidgetInfo structure.
  756. %
  757. %
  758. */
  759. static void XDrawWidgetText(display,window_info,text_info)
  760. Display
  761.   *display;
  762.  
  763. XWindowInfo
  764.   *window_info;
  765.  
  766. XWidgetInfo
  767.   *text_info;
  768. {
  769.   GC
  770.     widget_context;
  771.  
  772.   int
  773.     x,
  774.     y;
  775.  
  776.   register char
  777.     *p;
  778.  
  779.   unsigned int
  780.     height,
  781.     width;
  782.  
  783.   XFontStruct
  784.     *font_info;
  785.  
  786.   /*
  787.     Clear the text area.
  788.   */
  789.   widget_context=window_info->annotate_context;
  790.   if (text_info->raised)
  791.     XClearArea(display,window_info->id,text_info->x,text_info->y,
  792.       text_info->width,text_info->height,False);
  793.   else
  794.     {
  795.       XFillRectangle(display,window_info->id,widget_context,text_info->x,
  796.         text_info->y,text_info->width,text_info->height);
  797.       widget_context=window_info->highlight_context;
  798.     }
  799.   if (text_info->text == (char *) NULL)
  800.     return;
  801.   if (*text_info->text == '\0')
  802.     return;
  803.   /*
  804.     Insure text will fit within the window.
  805.   */
  806.   font_info=window_info->font_info;
  807.   width=text_info->width-font_info->max_bounds.width;
  808.   for (p=text_info->text+strlen(text_info->text)-1; p > text_info->text; p--)
  809.     if (XTextWidth(font_info,p,strlen(p)) > width)
  810.       {
  811.         p++;
  812.         break;
  813.       }
  814.   /*
  815.     Draw text.
  816.   */
  817.   height=font_info->ascent+font_info->descent;
  818.   x=text_info->x+(font_info->max_bounds.width >> 1);
  819.   y=text_info->y+((text_info->height-height) >> 1)+font_info->ascent;
  820.   XDrawString(display,window_info->id,widget_context,x,y,p,strlen(p));
  821.   if (p != text_info->text)
  822.     XDrawLine(display,window_info->id,window_info->annotate_context,
  823.       x,text_info->y,x,text_info->y+text_info->height-1);
  824. }
  825.  
  826. /*
  827. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  828. %                                                                             %
  829. %                                                                             %
  830. %                                                                             %
  831. %   X E d i t T e x t                                                         %
  832. %                                                                             %
  833. %                                                                             %
  834. %                                                                             %
  835. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  836. %
  837. %  Function XEditText edits a text string as indicated by the key symbol.
  838. %
  839. %  The format of the XEditText function is:
  840. %
  841. %      XEditText(display,text_info,key_symbol,text,state)
  842. %
  843. %  A description of each parameter follows:
  844. %
  845. %    o display: Specifies a connection to an X server;  returned from
  846. %      XOpenDisplay.
  847. %
  848. %    o text_info: Specifies a pointer to a XWidgetInfo structure.  It
  849. %      contains the extents of the text.
  850. %
  851. %    o key_symbol:  A X11 KeySym that indicates what editing function to
  852. %      perform to the text.
  853. %
  854. %    o text: A character string to insert into the text.
  855. %
  856. %    o state:  An unsigned long that indicates whether the key symbol is a
  857. %      control character or not.
  858. %
  859. %
  860. */
  861. static void XEditText(display,text_info,key_symbol,text,state)
  862. Display
  863.   *display;
  864.  
  865. XWidgetInfo
  866.   *text_info;
  867.  
  868. KeySym
  869.   key_symbol;
  870.  
  871. char
  872.   *text;
  873.  
  874. unsigned long
  875.   state;
  876. {
  877.   switch (key_symbol)
  878.   {
  879.     case XK_BackSpace:
  880.     {
  881.       /*
  882.         Erase one character.
  883.       */
  884.       if (text_info->cursor == text_info->text)
  885.         break;
  886.       text_info->cursor--;
  887.       (void) strcpy(text_info->cursor,text_info->cursor+1);
  888.       text_info->highlight=False;
  889.       break;
  890.     }
  891.     case XK_Delete:
  892.     {
  893.       /*
  894.         Erase the entire line of text.
  895.       */
  896.       *text_info->text='\0';
  897.       text_info->cursor=text_info->text;
  898.       text_info->highlight=False;
  899.       break;
  900.     }
  901.     case XK_Left:
  902.     {
  903.       /*
  904.         Move cursor one position left.
  905.       */
  906.       if (text_info->cursor == text_info->text)
  907.         break;
  908.       text_info->cursor--;
  909.       break;
  910.     }
  911.     case XK_Right:
  912.     {
  913.       /*
  914.         Move cursor one position right.
  915.       */
  916.       if (text_info->cursor == (text_info->text+strlen(text_info->text)))
  917.         break;
  918.       text_info->cursor++;
  919.       break;
  920.     }
  921.     default:
  922.     {
  923.       register char
  924.         *p,
  925.         *q;
  926.  
  927.       register int
  928.         i;
  929.  
  930.       if (state & ControlState)
  931.         break;
  932.       if (*text == '\0')
  933.         break;
  934.       if (((int) strlen(text_info->text)+1) >= MaxTextLength)
  935.         XBell(display,0);
  936.       else
  937.         {
  938.           /*
  939.             Insert a string into the text.
  940.           */
  941.           q=text_info->text+strlen(text_info->text)+strlen(text);
  942.           for (i=0; i <= (int) strlen(text_info->cursor); i++)
  943.           {
  944.             *q=(*(q-strlen(text)));
  945.             q--;
  946.           }
  947.           p=text;
  948.           for (i=0; i < (int) strlen(text); i++)
  949.             *text_info->cursor++=(*p++);
  950.           text_info->highlight=False;
  951.         }
  952.       break;
  953.     }
  954.   }
  955. }
  956.  
  957. /*
  958. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  959. %                                                                             %
  960. %                                                                             %
  961. %                                                                             %
  962. %   X G e t W i d g e t I n f o                                               %
  963. %                                                                             %
  964. %                                                                             %
  965. %                                                                             %
  966. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  967. %
  968. %  Function XGetWidgetInfo initializes the XWidgetInfo structure.
  969. %
  970. %  The format of the XGetWidgetInfo function is:
  971. %
  972. %      XGetWidgetInfo(text,widget_info)
  973. %
  974. %  A description of each parameter follows:
  975. %
  976. %    o text: A string of characters associated with the widget.
  977. %
  978. %    o widget_info: Specifies a pointer to a X11 XWidgetInfo structure.
  979. %
  980. %
  981. */
  982. static void XGetWidgetInfo(text,widget_info)
  983. char
  984.   *text;
  985.  
  986. XWidgetInfo
  987.   *widget_info;
  988. {
  989.   /*
  990.     Initialize widget info.
  991.   */
  992.    widget_info->id=(~0);
  993.    widget_info->bevel_width=3;
  994.    widget_info->width=1;
  995.    widget_info->height=1;
  996.    widget_info->x=0;
  997.    widget_info->y=0;
  998.    widget_info->min_y=0;
  999.    widget_info->max_y=0;
  1000.    widget_info->raised=True;
  1001.    widget_info->active=False;
  1002.    widget_info->trough=False;
  1003.    widget_info->highlight=False;
  1004.    widget_info->text=text;
  1005.    widget_info->cursor=text;
  1006.    if (text != (char *) NULL)
  1007.      widget_info->cursor+=strlen(text);
  1008.    widget_info->marker=text;
  1009. }
  1010.  
  1011. /*
  1012. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1013. %                                                                             %
  1014. %                                                                             %
  1015. %                                                                             %
  1016. %   X H i g h l i g h t W i d g e t                                           %
  1017. %                                                                             %
  1018. %                                                                             %
  1019. %                                                                             %
  1020. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1021. %
  1022. %  Function XHighlightWidget draws a highlighted border around a window.
  1023. %
  1024. %  The format of the XHighlightWidget function is:
  1025. %
  1026. %      XHighlightWidget(display,window_info,x,y)
  1027. %
  1028. %  A description of each parameter follows:
  1029. %
  1030. %    o display: Specifies a pointer to the Display structure;  returned from
  1031. %      XOpenDisplay.
  1032. %
  1033. %    o window_info: Specifies a pointer to a X11 XWindowInfo structure.
  1034. %
  1035. %    o x: Specifies an integer representing the rectangle offset in the
  1036. %      x-direction.
  1037. %
  1038. %    o y: Specifies an integer representing the rectangle offset in the
  1039. %      y-direction.
  1040. %
  1041. %
  1042. */
  1043. static void XHighlightWidget(display,window_info,x,y)
  1044. Display
  1045.   *display;
  1046.  
  1047. XWindowInfo
  1048.   *window_info;
  1049.  
  1050. int
  1051.   x,
  1052.   y;
  1053. {
  1054.   /*
  1055.     Draw the widget highlighting rectangle.
  1056.   */
  1057.   XSetBevelColor(display,window_info,True);
  1058.   XDrawRectangle(display,window_info->id,window_info->widget_context,x,y,
  1059.     window_info->width-(x << 1),window_info->height-(y << 1));
  1060.   XDrawRectangle(display,window_info->id,window_info->widget_context,x-1,y-1,
  1061.     window_info->width-(x << 1)+1,window_info->height-(y << 1)+1);
  1062.   XSetBevelColor(display,window_info,False);
  1063.   XDrawRectangle(display,window_info->id,window_info->widget_context,x-1,y-1,
  1064.     window_info->width-(x << 1),window_info->height-(y << 1));
  1065.   XSetFillStyle(display,window_info->widget_context,FillSolid);
  1066. }
  1067.  
  1068. /*
  1069. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1070. %                                                                             %
  1071. %                                                                             %
  1072. %                                                                             %
  1073. %   X S e t B e v e l C o l o r                                               %
  1074. %                                                                             %
  1075. %                                                                             %
  1076. %                                                                             %
  1077. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1078. %
  1079. %  Function XSetBevelColor sets the graphic context for drawing a beveled
  1080. %  border.
  1081. %
  1082. %  The format of the XSetBevelColor function is:
  1083. %
  1084. %      XSetBevelColor(display,window_info,raised)
  1085. %
  1086. %  A description of each parameter follows:
  1087. %
  1088. %    o display: Specifies a pointer to the Display structure;  returned from
  1089. %      XOpenDisplay.
  1090. %
  1091. %    o window_info: Specifies a pointer to a X11 XWindowInfo structure.
  1092. %
  1093. %    o raised: A value other than zero indicates the color show be a
  1094. %      "highlight" color, otherwise the "shadow" color is set.
  1095. %
  1096. %
  1097. */
  1098. static void XSetBevelColor(display,window_info,raised)
  1099. Display
  1100.   *display;
  1101.  
  1102. XWindowInfo
  1103.   *window_info;
  1104.  
  1105. unsigned int
  1106.   raised;
  1107. {
  1108.   if (window_info->depth == 1)
  1109.     {
  1110.       Pixmap
  1111.         stipple;
  1112.  
  1113.       /*
  1114.         Monochrome window.
  1115.       */
  1116.       XSetBackground(display,window_info->widget_context,
  1117.         XBlackPixel(display,window_info->screen));
  1118.       XSetForeground(display,window_info->widget_context,
  1119.         XWhitePixel(display,window_info->screen));
  1120.       XSetFillStyle(display,window_info->widget_context,FillOpaqueStippled);
  1121.       stipple=window_info->highlight_stipple;
  1122.       if (!raised)
  1123.         stipple=window_info->shadow_stipple;
  1124.       XSetStipple(display,window_info->widget_context,stipple);
  1125.     }
  1126.   else
  1127.     if (raised)
  1128.       XSetForeground(display,window_info->widget_context,
  1129.         window_info->pixel_info->highlight_color.pixel);
  1130.     else
  1131.       XSetForeground(display,window_info->widget_context,
  1132.         window_info->pixel_info->shadow_color.pixel);
  1133. }
  1134.  
  1135. /*
  1136. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1137. %                                                                             %
  1138. %                                                                             %
  1139. %                                                                             %
  1140. %   X S e t M a t t e C o l o r                                               %
  1141. %                                                                             %
  1142. %                                                                             %
  1143. %                                                                             %
  1144. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1145. %
  1146. %  Function XSetMatteColor sets the graphic context for drawing the matte.
  1147. %
  1148. %  The format of the XSetMatteColor function is:
  1149. %
  1150. %      XSetMatteColor(display,window_info,raised)
  1151. %
  1152. %  A description of each parameter follows:
  1153. %
  1154. %    o display: Specifies a pointer to the Display structure;  returned from
  1155. %      XOpenDisplay.
  1156. %
  1157. %    o window_info: Specifies a pointer to a X11 XWindowInfo structure.
  1158. %
  1159. %    o raised: A value other than zero indicates the matte is active.
  1160. %
  1161. %
  1162. */
  1163. static void XSetMatteColor(display,window_info,raised)
  1164. Display
  1165.   *display;
  1166.  
  1167. XWindowInfo
  1168.   *window_info;
  1169.  
  1170. unsigned int
  1171.   raised;
  1172. {
  1173.   if (window_info->depth == 1)
  1174.     {
  1175.       /*
  1176.         Monochrome window.
  1177.       */
  1178.       if (raised)
  1179.         XSetForeground(display,window_info->widget_context,
  1180.           XWhitePixel(display,window_info->screen));
  1181.       else
  1182.         XSetForeground(display,window_info->widget_context,
  1183.           XBlackPixel(display,window_info->screen));
  1184.     }
  1185.   else
  1186.     if (raised)
  1187.       XSetForeground(display,window_info->widget_context,
  1188.         window_info->pixel_info->matte_color.pixel);
  1189.     else
  1190.       XSetForeground(display,window_info->widget_context,
  1191.         window_info->pixel_info->depth_color.pixel);
  1192. }
  1193.  
  1194. /*
  1195. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1196. %                                                                             %
  1197. %                                                                             %
  1198. %                                                                             %
  1199. %   X S e t T e x t C o l o r                                                 %
  1200. %                                                                             %
  1201. %                                                                             %
  1202. %                                                                             %
  1203. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1204. %
  1205. %  Function XSetTextColor sets the graphic context for drawing text on a
  1206. %  matte.
  1207. %
  1208. %  The format of the XSetTextColor function is:
  1209. %
  1210. %      XSetTextColor(display,window_info,raised)
  1211. %
  1212. %  A description of each parameter follows:
  1213. %
  1214. %    o display: Specifies a pointer to the Display structure;  returned from
  1215. %      XOpenDisplay.
  1216. %
  1217. %    o window_info: Specifies a pointer to a X11 XWindowInfo structure.
  1218. %
  1219. %    o raised: A value other than zero indicates the color show be a
  1220. %      "highlight" color, otherwise the "shadow" color is set.
  1221. %
  1222. %
  1223. */
  1224. static void XSetTextColor(display,window_info,raised)
  1225. Display
  1226.   *display;
  1227.  
  1228. XWindowInfo
  1229.   *window_info;
  1230.  
  1231. unsigned int
  1232.   raised;
  1233. {
  1234.   if (window_info->depth == 1)
  1235.     {
  1236.       /*
  1237.         Monochrome window.
  1238.       */
  1239.       if (raised)
  1240.         XSetForeground(display,window_info->widget_context,
  1241.           XBlackPixel(display,window_info->screen));
  1242.       else
  1243.         XSetForeground(display,window_info->widget_context,
  1244.           XWhitePixel(display,window_info->screen));
  1245.     }
  1246.   else
  1247.     XSetForeground(display,window_info->widget_context,
  1248.       window_info->pixel_info->foreground_color.pixel);
  1249. }
  1250.  
  1251. /*
  1252. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1253. %                                                                             %
  1254. %                                                                             %
  1255. %                                                                             %
  1256. %   X W i d g e t E v e n t                                                   %
  1257. %                                                                             %
  1258. %                                                                             %
  1259. %                                                                             %
  1260. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1261. %
  1262. %  Function XWidgetEvent returns True if the any event on the X server queue
  1263. %  is associated with the widget window.
  1264. %
  1265. %  The format of the XWidgetEvent function is:
  1266. %
  1267. %      XWidgetEvent(display,event,data)
  1268. %
  1269. %  A description of each parameter follows:
  1270. %
  1271. %    o display: Specifies a pointer to the Display structure;  returned from
  1272. %      XOpenDisplay.
  1273. %
  1274. %    o event: Specifies a pointer to a X11 XEvent structure.
  1275. %
  1276. %    o data: Specifies a pointer to a XWindows structure.
  1277. %
  1278. %
  1279. */
  1280. static int XWidgetEvent(display,event,data)
  1281. Display
  1282.   *display;
  1283.  
  1284. XEvent
  1285.   *event;
  1286.  
  1287. char
  1288.   *data;
  1289. {
  1290.   XWindows
  1291.     *window;
  1292.  
  1293.   window=(XWindows *) data;
  1294.   if (event->xany.window == window->popup.id)
  1295.     return(True);
  1296.   switch (event->type)
  1297.   {
  1298.     case Expose:
  1299.     {
  1300.       if (event->xany.window == window->image.id)
  1301.         return(True);
  1302.       return(False);
  1303.     }
  1304.     case ButtonPress:
  1305.     case ButtonRelease:
  1306.     case KeyPress:
  1307.     case KeyRelease:
  1308.     case MotionNotify:
  1309.     case SelectionNotify:
  1310.       return(True);
  1311.     default:
  1312.       return(False);
  1313.   }
  1314. }
  1315.  
  1316. /*
  1317. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1318. %                                                                             %
  1319. %                                                                             %
  1320. %                                                                             %
  1321. %   X C o l o r B r o w s e r W i d g e t                                     %
  1322. %                                                                             %
  1323. %                                                                             %
  1324. %                                                                             %
  1325. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1326. %
  1327. %  Function XColorBrowserWidget displays a popup window with a color query to
  1328. %  the user.  The user keys a reply and presses the Action or Cancel button
  1329. %  to exit.  The typed text is returned as the reply function parameter.
  1330. %
  1331. %  The format of the XColorBrowserWidget routine is:
  1332. %
  1333. %    XColorBrowserWidget(display,resource_info,window,action,reply)
  1334. %
  1335. %  A description of each parameter follows:
  1336. %
  1337. %    o display: Specifies a connection to an X server;  returned from
  1338. %      XOpenDisplay.
  1339. %
  1340. %    o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
  1341. %
  1342. %    o window: Specifies a pointer to a XWindows structure.
  1343. %
  1344. %    o action: Specifies a pointer to the action of this widget.
  1345. %
  1346. %    o reply: The response from the user is returned in this parameter.
  1347. %
  1348. %
  1349. */
  1350. void XColorBrowserWidget(display,resource_info,window,action,reply)
  1351. Display
  1352.   *display;
  1353.  
  1354. XResourceInfo
  1355.   *resource_info;
  1356.  
  1357. XWindows
  1358.   *window;
  1359.  
  1360. char
  1361.   *action,
  1362.   *reply;
  1363. {
  1364. #define CancelButtonText  "Cancel"
  1365. #define ColornameText  "Name:"
  1366. #define ColorPatternText  "Pattern:"
  1367. #define GrabButtonText  "Grab"
  1368. #define ResetButtonText  "Reset"
  1369.  
  1370.   char
  1371.     **colorlist,
  1372.     primary_selection[MaxTextLength],
  1373.     reset_pattern[MaxTextLength],
  1374.     text[MaxTextLength];
  1375.  
  1376.   int
  1377.     colors,
  1378.     x,
  1379.     x_offset,
  1380.     y,
  1381.     y_offset;
  1382.  
  1383.   register int
  1384.     i;
  1385.  
  1386.   static char
  1387.     glob_pattern[MaxTextLength] = "*";
  1388.  
  1389.   unsigned int
  1390.     delay,
  1391.     height,
  1392.     limit,
  1393.     mask,
  1394.     status,
  1395.     text_width,
  1396.     visible_colors,
  1397.     width;
  1398.  
  1399.   unsigned long
  1400.     state;
  1401.  
  1402.   Window
  1403.     child,
  1404.     root_window;
  1405.  
  1406.   XColor
  1407.     color;
  1408.  
  1409.   XEvent
  1410.     event;
  1411.  
  1412.   XFontStruct
  1413.     *font_info;
  1414.  
  1415.   XTextProperty
  1416.     window_name;
  1417.  
  1418.   XWidgetInfo
  1419.     action_info,
  1420.     cancel_info,
  1421.     expose_info,
  1422.     grab_info,
  1423.     list_info,
  1424.     mode_info,
  1425.     north_info,
  1426.     reply_info,
  1427.     reset_info,
  1428.     scroll_info,
  1429.     selection_info,
  1430.     slider_info,
  1431.     south_info,
  1432.     text_info;
  1433.  
  1434.   XWindowChanges
  1435.     window_changes;
  1436.  
  1437.   /*
  1438.     Get color list and sort in ascending order.
  1439.   */
  1440.   XDefineCursor(display,window->image.id,window->image.busy_cursor);
  1441.   XFlush(display);
  1442.   (void) strcpy(reset_pattern,"*");
  1443.   colorlist=XListColors(glob_pattern,&colors);
  1444.   if (colorlist == (char **) NULL)
  1445.     {
  1446.       /*
  1447.         Pattern failed, obtain all the colors.
  1448.       */
  1449.       XNoticeWidget(display,resource_info,window,
  1450.         "Unable to obtain colors names",glob_pattern);
  1451.       (void) strcpy(glob_pattern,"*");
  1452.       colorlist=XListColors(glob_pattern,&colors);
  1453.       if (colorlist == (char **) NULL)
  1454.         {
  1455.           XNoticeWidget(display,resource_info,window,
  1456.             "Unable to obtain colors names",glob_pattern);
  1457.           return;
  1458.         }
  1459.     }
  1460.   /*
  1461.     Determine popup window attributes.
  1462.   */
  1463.   font_info=window->popup.font_info;
  1464.   text_width=0;
  1465.   for (i=0; i < colors; i++)
  1466.     if (XTextWidth(font_info,colorlist[i],strlen(colorlist[i])) > text_width)
  1467.       text_width=XTextWidth(font_info,colorlist[i],strlen(colorlist[i]));
  1468.   width=XTextWidth(font_info,action,strlen(action));
  1469.   if (XTextWidth(font_info,CancelButtonText,strlen(CancelButtonText)) > width)
  1470.     width=XTextWidth(font_info,CancelButtonText,strlen(CancelButtonText));
  1471.   if (XTextWidth(font_info,ResetButtonText,strlen(ResetButtonText)) > width)
  1472.     width=XTextWidth(font_info,ResetButtonText,strlen(ResetButtonText));
  1473.   if (XTextWidth(font_info,GrabButtonText,strlen(GrabButtonText)) > width)
  1474.     width=XTextWidth(font_info,GrabButtonText,strlen(GrabButtonText));
  1475.   width+=font_info->max_bounds.width;
  1476.   if (XTextWidth(font_info,ColorPatternText,strlen(ColorPatternText)) > width)
  1477.     width=XTextWidth(font_info,ColorPatternText,strlen(ColorPatternText));
  1478.   if (XTextWidth(font_info,ColornameText,strlen(ColornameText)) > width)
  1479.     width=XTextWidth(font_info,ColornameText,strlen(ColornameText));
  1480.   height=font_info->ascent+font_info->descent;
  1481.   window->popup.width=width+text_width+6*font_info->max_bounds.width;
  1482.   window->popup.height=
  1483.     ((81*height) >> 2)+((13*font_info->max_bounds.width) >> 1)+4;
  1484.   window->popup.min_width=width+25*XTextWidth(font_info,"#",1)+
  1485.     4*font_info->max_bounds.width;
  1486.   window->popup.min_height=
  1487.     ((23*height) >> 1)+((13*font_info->max_bounds.width) >> 1)+4;
  1488.   /*
  1489.     Position popup window.
  1490.   */
  1491.   XQueryPointer(display,XRootWindow(display,window->popup.screen),&root_window,
  1492.     &root_window,&x,&y,&window->popup.x,&window->popup.y,&mask);
  1493.   if (window->popup.width < window->popup.min_width)
  1494.     window->popup.width=window->popup.min_width;
  1495.   window->popup.x-=((3*window->popup.width) >> 2);
  1496.   limit=XDisplayWidth(display,window->popup.screen)-window->popup.width;
  1497.   if (window->popup.x < 0)
  1498.     window->popup.x=0;
  1499.   else
  1500.     if (window->popup.x > limit)
  1501.       window->popup.x=limit;
  1502.   if (window->popup.height < window->popup.min_height)
  1503.     window->popup.height=window->popup.min_height;
  1504.   window->popup.y-=(window->popup.height >> 1);
  1505.   limit=XDisplayHeight(display,window->popup.screen)-window->popup.height;
  1506.   if (window->popup.y < 0)
  1507.     window->popup.y=0;
  1508.   else
  1509.     if (window->popup.y > limit)
  1510.       window->popup.y=limit;
  1511.   /*
  1512.     Map popup window.
  1513.   */
  1514.   (void) sprintf(window->popup.name,"Browse and Select a Color");
  1515.   (void) XStringListToTextProperty(&window->popup.name,1,&window_name);
  1516.   XSetWMName(display,window->popup.id,&window_name);
  1517.   window_changes.width=window->popup.width;
  1518.   window_changes.height=window->popup.height;
  1519.   window_changes.x=window->popup.x;
  1520.   window_changes.y=window->popup.y;
  1521.   XReconfigureWMWindow(display,window->popup.id,window->popup.screen,CWWidth |
  1522.     CWHeight | CWX | CWY,&window_changes);
  1523.   XMapRaised(display,window->popup.id);
  1524.   /*
  1525.     Respond to X events.
  1526.   */
  1527.   XGetWidgetInfo((char *) NULL,&north_info);
  1528.   XGetWidgetInfo((char *) NULL,&south_info);
  1529.   visible_colors=0;
  1530.   delay=SuspendTime << 2;
  1531.   state=UpdateConfigurationState;
  1532.   do
  1533.   {
  1534.     /*
  1535.       Wait for next event.
  1536.     */
  1537.     if (north_info.raised && south_info.raised)
  1538.       XIfEvent(display,&event,XWidgetEvent,(char *) window);
  1539.     else
  1540.       {
  1541.         /*
  1542.           Brief delay before advancing scroll bar.
  1543.         */
  1544.         XDelay(display,delay);
  1545.         XCheckMaskEvent(display,ButtonReleaseMask,&event);
  1546.         delay=SuspendTime;
  1547.       }
  1548.     switch (event.type)
  1549.     {
  1550.       case ButtonPress:
  1551.       {
  1552.         if (event.xbutton.window != window->popup.id)
  1553.           {
  1554.             XBell(display,0);
  1555.             break;
  1556.           }
  1557.         if (MatteIsActive(slider_info,event.xbutton))
  1558.           {
  1559.             /*
  1560.               Track slider.
  1561.             */
  1562.             slider_info.active=True;
  1563.             break;
  1564.           }
  1565.         if (MatteIsActive(north_info,event.xbutton))
  1566.           if (slider_info.id > 0)
  1567.             {
  1568.               /*
  1569.                 Move slider up.
  1570.               */
  1571.               north_info.raised=False;
  1572.               slider_info.id--;
  1573.               state|=RedrawListState;
  1574.               break;
  1575.             }
  1576.         if (MatteIsActive(south_info,event.xbutton))
  1577.           if (slider_info.id < colors)
  1578.             {
  1579.               /*
  1580.                 Move slider down.
  1581.               */
  1582.               south_info.raised=False;
  1583.               slider_info.id++;
  1584.               state|=RedrawListState;
  1585.               break;
  1586.             }
  1587.         if (MatteIsActive(scroll_info,event.xbutton))
  1588.           {
  1589.             /*
  1590.               Move slider.
  1591.             */
  1592.             if (event.xbutton.y < slider_info.y)
  1593.               slider_info.id-=(visible_colors-1);
  1594.             else
  1595.               slider_info.id+=(visible_colors-1);
  1596.             state|=RedrawListState;
  1597.             break;
  1598.           }
  1599.         if (MatteIsActive(list_info,event.xbutton))
  1600.           {
  1601.             unsigned int
  1602.               id;
  1603.  
  1604.             /*
  1605.               User pressed list matte.
  1606.             */
  1607.             id=slider_info.id+(event.xbutton.y-(list_info.y+(height >> 1))+1)/
  1608.               selection_info.height;
  1609.             if (id >= colors)
  1610.               break;
  1611.             (void) strcpy(reply_info.text,colorlist[id]);
  1612.             reply_info.highlight=False;
  1613.             reply_info.marker=reply_info.text;
  1614.             reply_info.cursor=reply_info.text+strlen(reply_info.text);
  1615.             XDrawMatteText(display,&window->popup,&reply_info);
  1616.             state|=RedrawActionState;
  1617.             if (id == list_info.id)
  1618.               {
  1619.                 (void) strcpy(glob_pattern,reply_info.text);
  1620.                 state|=UpdateListState;
  1621.               }
  1622.             selection_info.id=(~0);
  1623.             list_info.id=id;
  1624.             state|=RedrawListState;
  1625.             break;
  1626.           }
  1627.         if (MatteIsActive(grab_info,event.xbutton))
  1628.           {
  1629.             /*
  1630.               User pressed Grab button.
  1631.             */
  1632.             grab_info.raised=False;
  1633.             XDrawBeveledButton(display,&window->popup,&grab_info);
  1634.             break;
  1635.           }
  1636.         if (MatteIsActive(reset_info,event.xbutton))
  1637.           {
  1638.             /*
  1639.               User pressed Reset button.
  1640.             */
  1641.             reset_info.raised=False;
  1642.             XDrawBeveledButton(display,&window->popup,&reset_info);
  1643.             break;
  1644.           }
  1645.         if (MatteIsActive(action_info,event.xbutton))
  1646.           {
  1647.             /*
  1648.               User pressed action button.
  1649.             */
  1650.             action_info.raised=False;
  1651.             XDrawBeveledButton(display,&window->popup,&action_info);
  1652.             break;
  1653.           }
  1654.         if (MatteIsActive(cancel_info,event.xbutton))
  1655.           {
  1656.             /*
  1657.               User pressed Cancel button.
  1658.             */
  1659.             cancel_info.raised=False;
  1660.             XDrawBeveledButton(display,&window->popup,&cancel_info);
  1661.             break;
  1662.           }
  1663.         if ((event.xbutton.button == Button3) &&
  1664.             (event.xbutton.state & Mod1Mask))
  1665.           {
  1666.             /*
  1667.               Convert Alt-Matte3 to Button2.
  1668.             */
  1669.             event.xbutton.button=Button2;
  1670.             event.xbutton.state&=(~Mod1Mask);
  1671.           }
  1672.         if (!MatteIsActive(reply_info,event.xbutton))
  1673.           break;
  1674.         if (event.xbutton.button != Button2)
  1675.           {
  1676.             static Time
  1677.               click_time;
  1678.  
  1679.             /*
  1680.               Move text cursor to position of button press.
  1681.             */
  1682.             x=event.xbutton.x-reply_info.x-(font_info->max_bounds.width >> 2);
  1683.             for (i=1; i <= (int) strlen(reply_info.marker); i++)
  1684.               if (XTextWidth(font_info,reply_info.marker,i) > x)
  1685.                 break;
  1686.             reply_info.cursor=reply_info.marker+i-1;
  1687.             if (event.xbutton.time < (click_time+DoubleClick))
  1688.               {
  1689.                 /*
  1690.                   Become the XA_PRIMARY selection owner.
  1691.                 */
  1692.                 (void) strcpy(primary_selection,reply_info.text);
  1693.                 XSetSelectionOwner(display,XA_PRIMARY,window->popup.id,
  1694.                   event.xbutton.time);
  1695.                 reply_info.highlight=XGetSelectionOwner(display,XA_PRIMARY) ==
  1696.                   window->popup.id;
  1697.               }
  1698.             XDrawMatteText(display,&window->popup,&reply_info);
  1699.             click_time=event.xbutton.time;
  1700.             break;
  1701.           }
  1702.         /*
  1703.           Request primary selection.
  1704.         */
  1705.         XConvertSelection(display,XA_PRIMARY,XA_STRING,XA_STRING,
  1706.           window->popup.id,event.xbutton.time);
  1707.         break;
  1708.       }
  1709.       case ButtonRelease:
  1710.       {
  1711.         if (!north_info.raised)
  1712.           {
  1713.             /*
  1714.               User released up button.
  1715.             */
  1716.             delay=SuspendTime << 2;
  1717.             north_info.raised=True;
  1718.             XDrawTriangleNorth(display,&window->popup,&north_info);
  1719.           }
  1720.         if (!south_info.raised)
  1721.           {
  1722.             /*
  1723.               User released down button.
  1724.             */
  1725.             delay=SuspendTime << 2;
  1726.             south_info.raised=True;
  1727.             XDrawTriangleSouth(display,&window->popup,&south_info);
  1728.           }
  1729.         if (slider_info.active)
  1730.           {
  1731.             /*
  1732.               Stop tracking slider.
  1733.             */
  1734.             slider_info.active=False;
  1735.             break;
  1736.           }
  1737.         if (!grab_info.raised)
  1738.           {
  1739.             if (event.xbutton.window == window->popup.id)
  1740.               if (MatteIsActive(grab_info,event.xbutton))
  1741.                 {
  1742.                   unsigned int
  1743.                     status;
  1744.  
  1745.                   XColor
  1746.                     color;
  1747.  
  1748.                   /*
  1749.                     Select a pen color from the X server.
  1750.                   */
  1751.                   status=XGetWindowColor(display,&color);
  1752.                   if (status != False)
  1753.                     {
  1754.                       (void) sprintf(reply_info.text,"#%02x%02x%02x",
  1755.                         color.red >> 8,color.green >> 8,color.blue >> 8);
  1756.                       reply_info.marker=reply_info.text;
  1757.                       reply_info.cursor=reply_info.text+strlen(reply_info.text);
  1758.                       XDrawMatteText(display,&window->popup,&reply_info);
  1759.                       state|=RedrawActionState;
  1760.                     }
  1761.                 }
  1762.             grab_info.raised=True;
  1763.             XDrawBeveledButton(display,&window->popup,&grab_info);
  1764.           }
  1765.         if (!reset_info.raised)
  1766.           {
  1767.             if (event.xbutton.window == window->popup.id)
  1768.               if (MatteIsActive(reset_info,event.xbutton))
  1769.                 {
  1770.                   (void) strcpy(glob_pattern,reset_pattern);
  1771.                   state|=UpdateListState;
  1772.                 }
  1773.             reset_info.raised=True;
  1774.             XDrawBeveledButton(display,&window->popup,&reset_info);
  1775.           }
  1776.         if (!action_info.raised)
  1777.           {
  1778.             if (event.xbutton.window == window->popup.id)
  1779.               if (MatteIsActive(action_info,event.xbutton))
  1780.                 if (*reply_info.text == '\0')
  1781.                   XBell(display,0);
  1782.                 else
  1783.                   state|=ExitState;
  1784.             action_info.raised=True;
  1785.             XDrawBeveledButton(display,&window->popup,&action_info);
  1786.           }
  1787.         if (!cancel_info.raised)
  1788.           {
  1789.             if (event.xbutton.window == window->popup.id)
  1790.               if (MatteIsActive(cancel_info,event.xbutton))
  1791.                 {
  1792.                   *reply_info.text='\0';
  1793.                   state|=ExitState;
  1794.                 }
  1795.             cancel_info.raised=True;
  1796.             XDrawBeveledButton(display,&window->popup,&cancel_info);
  1797.           }
  1798.         if (!MatteIsActive(reply_info,event.xbutton))
  1799.           break;
  1800.         break;
  1801.       }
  1802.       case ConfigureNotify:
  1803.       {
  1804.         /*
  1805.           Update widget configuration.
  1806.         */
  1807.         if (event.xconfigure.window != window->popup.id)
  1808.           break;
  1809.         if ((window->popup.width != event.xconfigure.width) ||
  1810.             (window->popup.height != event.xconfigure.height))
  1811.           state|=RedrawWidgetState;
  1812.         window->popup.width=Max(event.xconfigure.width,window->popup.min_width);
  1813.         window->popup.height=
  1814.           Max(event.xconfigure.height,window->popup.min_height);
  1815.         state|=UpdateConfigurationState;
  1816.         break;
  1817.       }
  1818.       case Expose:
  1819.       {
  1820.         if (event.xexpose.window == window->image.id)
  1821.           {
  1822.             XRefreshWindow(display,&window->image,&event);
  1823.             break;
  1824.           }
  1825.         if (event.xexpose.window == window->magnify.id)
  1826.           if (event.xexpose.count == 0)
  1827.             if (window->magnify.mapped)
  1828.               {
  1829.                 XMakeMagnifyImage(display,resource_info,window);
  1830.                 break;
  1831.               }
  1832.         if (event.xexpose.window != window->popup.id)
  1833.           break;
  1834.         if (event.xexpose.count != 0)
  1835.           break;
  1836.         state|=RedrawWidgetState;
  1837.         break;
  1838.       }
  1839.       case KeyPress:
  1840.       {
  1841.         static char
  1842.           command[MaxTextLength];
  1843.  
  1844.         static int
  1845.           length;
  1846.  
  1847.         static KeySym
  1848.           key_symbol;
  1849.  
  1850.         if (event.xkey.window != window->popup.id)
  1851.           break;
  1852.         /*
  1853.           Respond to a user key press.
  1854.         */
  1855.         length=XLookupString((XKeyEvent *) &event.xkey,command,sizeof(command),
  1856.           &key_symbol,(XComposeStatus *) NULL);
  1857.         *(command+length)='\0';
  1858.         if (key_symbol == XK_Up)
  1859.           if (MatteIsActive(scroll_info,event.xkey))
  1860.             if (slider_info.id > 0)
  1861.               {
  1862.                 /*
  1863.                   Move slider up.
  1864.                 */
  1865.                 slider_info.id--;
  1866.                 state|=RedrawListState;
  1867.                 break;
  1868.               }
  1869.         if (key_symbol == XK_Down)
  1870.           if (MatteIsActive(scroll_info,event.xkey))
  1871.             if (slider_info.id < colors)
  1872.               {
  1873.                 /*
  1874.                   Move slider down.
  1875.                 */
  1876.                 slider_info.id++;
  1877.                 state|=RedrawListState;
  1878.                 break;
  1879.               }
  1880.         if (!MatteIsActive(reply_info,event.xkey))
  1881.           break;
  1882.         if ((key_symbol == XK_Return) || (key_symbol == XK_KP_Enter))
  1883.           {
  1884.             /*
  1885.               Read new color or glob patterm.
  1886.             */
  1887.             if (*reply_info.text == '\0')
  1888.               break;
  1889.             (void) strcpy(glob_pattern,reply_info.text);
  1890.             state|=UpdateListState;
  1891.             break;
  1892.           }
  1893.         if (key_symbol == XK_Control_L)
  1894.           {
  1895.             state|=ControlState;
  1896.             break;
  1897.           }
  1898.         if (state & ControlState)
  1899.           switch (key_symbol)
  1900.           {
  1901.             case XK_u:
  1902.             case XK_U:
  1903.             {
  1904.               key_symbol=XK_Delete;
  1905.               break;
  1906.             }
  1907.             default:
  1908.               break;
  1909.           }
  1910.         XEditText(display,&reply_info,key_symbol,command,state);
  1911.         XDrawMatteText(display,&window->popup,&reply_info);
  1912.         status=XParseColor(display,window->popup.map_info->colormap,
  1913.           reply_info.text,&color);
  1914.         if (status != 0)
  1915.           state|=RedrawActionState;
  1916.         break;
  1917.       }
  1918.       case KeyRelease:
  1919.       {
  1920.         static char
  1921.           command[MaxTextLength];
  1922.  
  1923.         static KeySym
  1924.           key_symbol;
  1925.  
  1926.         if (event.xkey.window != window->popup.id)
  1927.           break;
  1928.         /*
  1929.           Respond to a user key release.
  1930.         */
  1931.         (void) XLookupString((XKeyEvent *) &event.xkey,command,sizeof(command),
  1932.           &key_symbol,(XComposeStatus *) NULL);
  1933.         if (key_symbol == XK_Control_L)
  1934.           state&=(~ControlState);
  1935.         break;
  1936.       }
  1937.       case MotionNotify:
  1938.       {
  1939.         /*
  1940.           Discard pending button motion events.
  1941.         */
  1942.         while (XCheckMaskEvent(display,ButtonMotionMask,&event));
  1943.         if (event.xmotion.window == window->image.id)
  1944.           {
  1945.             XTranslateCoordinates(display,event.xmotion.window,window->popup.id,
  1946.               0,0,&x_offset,&y_offset,&child);
  1947.             event.xmotion.x+=x_offset;
  1948.             event.xmotion.y+=y_offset;
  1949.           }
  1950.         if (slider_info.active)
  1951.           {
  1952.             /*
  1953.               Move slider matte.
  1954.             */
  1955.             slider_info.y=event.xmotion.y-
  1956.               ((slider_info.height+slider_info.bevel_width) >> 1)+1;
  1957.             if (slider_info.y < slider_info.min_y)
  1958.               slider_info.y=slider_info.min_y;
  1959.             if (slider_info.y > slider_info.max_y)
  1960.               slider_info.y=slider_info.max_y;
  1961.             slider_info.id=(colors*(slider_info.y-slider_info.min_y+1))/
  1962.               (slider_info.max_y-slider_info.min_y+1);
  1963.             state|=RedrawListState;
  1964.             break;
  1965.           }
  1966.         if (grab_info.raised == MatteIsActive(grab_info,event.xmotion))
  1967.           {
  1968.             /*
  1969.               Grab button status changed.
  1970.             */
  1971.             grab_info.raised=!grab_info.raised;
  1972.             XDrawBeveledButton(display,&window->popup,&grab_info);
  1973.             break;
  1974.           }
  1975.         if (reset_info.raised == MatteIsActive(reset_info,event.xmotion))
  1976.           {
  1977.             /*
  1978.               Reset button status changed.
  1979.             */
  1980.             reset_info.raised=!reset_info.raised;
  1981.             XDrawBeveledButton(display,&window->popup,&reset_info);
  1982.             break;
  1983.           }
  1984.         if (action_info.raised == MatteIsActive(action_info,event.xmotion))
  1985.           {
  1986.             /*
  1987.               Action button status changed.
  1988.             */
  1989.             action_info.raised=!action_info.raised;
  1990.             XDrawBeveledButton(display,&window->popup,&action_info);
  1991.             break;
  1992.           }
  1993.         if (cancel_info.raised == MatteIsActive(cancel_info,event.xmotion))
  1994.           {
  1995.             /*
  1996.               Cancel button status changed.
  1997.             */
  1998.             cancel_info.raised=!cancel_info.raised;
  1999.             XDrawBeveledButton(display,&window->popup,&cancel_info);
  2000.             break;
  2001.           }
  2002.         break;
  2003.       }
  2004.       case SelectionClear:
  2005.       {
  2006.         reply_info.highlight=False;
  2007.         XDrawMatteText(display,&window->popup,&reply_info);
  2008.         break;
  2009.       }
  2010.       case SelectionNotify:
  2011.       {
  2012.         Atom
  2013.           type;
  2014.  
  2015.         int
  2016.           format,
  2017.           status;
  2018.  
  2019.         unsigned char
  2020.           *data;
  2021.  
  2022.         unsigned long
  2023.           after,
  2024.           length;
  2025.  
  2026.         /*
  2027.           Obtain response from primary selection.
  2028.         */
  2029.         if (event.xselection.property == (Atom) None)
  2030.           break;
  2031.         status=XGetWindowProperty(display,event.xselection.requestor,
  2032.           event.xselection.property,0L,2047L,True,XA_STRING,&type,&format,
  2033.           &length,&after,&data);
  2034.         if ((status != Success) || (type != XA_STRING) || (format == 32) ||
  2035.             (length == 0))
  2036.           break;
  2037.         if ((strlen(reply_info.text)+length) >= MaxTextLength)
  2038.           XBell(display,0);
  2039.         else
  2040.           {
  2041.             /*
  2042.               Insert primary selection in reply text.
  2043.             */
  2044.             *(data+length)='\0';
  2045.             XEditText(display,&reply_info,(KeySym) XK_Insert,(char *) data,
  2046.               state);
  2047.             XDrawMatteText(display,&window->popup,&reply_info);
  2048.             state|=RedrawActionState;
  2049.           }
  2050.         XFree((void *) data);
  2051.         break;
  2052.       }
  2053.       case SelectionRequest:
  2054.       {
  2055.         XSelectionEvent
  2056.           notify;
  2057.  
  2058.         XSelectionRequestEvent
  2059.           *request;
  2060.  
  2061.         if (!reply_info.highlight)
  2062.           break;
  2063.         /*
  2064.           Set primary selection.
  2065.         */
  2066.         request=(&(event.xselectionrequest));
  2067.         XChangeProperty(request->display,request->requestor,request->property,
  2068.           request->target,8,PropModeReplace,primary_selection,
  2069.           strlen(primary_selection));
  2070.         notify.type=SelectionNotify;
  2071.         notify.display=request->display;
  2072.         notify.requestor=request->requestor;
  2073.         notify.selection=request->selection;
  2074.         notify.target=request->target;
  2075.         notify.time=request->time;
  2076.         if (request->property == None)
  2077.           notify.property=request->target;
  2078.         else
  2079.           notify.property=request->property;
  2080.         (void) XSendEvent(request->display,request->requestor,False,0,
  2081.           (XEvent *) ¬ify);
  2082.       }
  2083.       default:
  2084.         break;
  2085.     }
  2086.     if (state & UpdateConfigurationState)
  2087.       {
  2088.         /*
  2089.           Initialize button information.
  2090.         */
  2091.         XGetWidgetInfo(CancelButtonText,&cancel_info);
  2092.         cancel_info.width=width;
  2093.         cancel_info.height=(3*height) >> 1;
  2094.         cancel_info.x=window->popup.width-cancel_info.width-
  2095.           font_info->max_bounds.width-2;
  2096.         cancel_info.y=window->popup.height-cancel_info.height-
  2097.           font_info->max_bounds.width;
  2098.         XGetWidgetInfo(action,&action_info);
  2099.         action_info.width=width;
  2100.         action_info.height=(3*height) >> 1;
  2101.         action_info.x=cancel_info.x-(cancel_info.width+
  2102.           (font_info->max_bounds.width >> 1)+(action_info.bevel_width << 1));
  2103.         action_info.y=cancel_info.y;
  2104.         XGetWidgetInfo(GrabButtonText,&grab_info);
  2105.         grab_info.width=width;
  2106.         grab_info.height=(3*height) >> 1;
  2107.         grab_info.x=font_info->max_bounds.width;
  2108.         grab_info.y=((5*font_info->max_bounds.width) >> 1)+height;
  2109.         XGetWidgetInfo(ResetButtonText,&reset_info);
  2110.         reset_info.width=width;
  2111.         reset_info.height=(3*height) >> 1;
  2112.         reset_info.x=font_info->max_bounds.width;
  2113.         reset_info.y=grab_info.y+grab_info.height+font_info->max_bounds.width;
  2114.         /*
  2115.           Initialize reply information.
  2116.         */
  2117.         XGetWidgetInfo(reply,&reply_info);
  2118.         reply_info.raised=False;
  2119.         reply_info.bevel_width--;
  2120.         reply_info.width=window->popup.width-width-
  2121.           ((6*font_info->max_bounds.width) >> 1);
  2122.         reply_info.height=height << 1;
  2123.         reply_info.x=width+(font_info->max_bounds.width << 1);
  2124.         reply_info.y=
  2125.           action_info.y-reply_info.height-font_info->max_bounds.width;
  2126.         /*
  2127.           Initialize mode information.
  2128.         */
  2129.         XGetWidgetInfo((char *) NULL,&mode_info);
  2130.         mode_info.bevel_width=0;
  2131.         mode_info.width=action_info.x-reply_info.x-font_info->max_bounds.width;
  2132.         mode_info.height=action_info.height;
  2133.         mode_info.x=reply_info.x;
  2134.         mode_info.y=action_info.y;
  2135.         /*
  2136.           Initialize scroll information.
  2137.         */
  2138.         XGetWidgetInfo((char *) NULL,&scroll_info);
  2139.         scroll_info.bevel_width--;
  2140.         scroll_info.width=height;
  2141.         scroll_info.height=
  2142.           reply_info.y-grab_info.y-(font_info->max_bounds.width >> 1);
  2143.         scroll_info.x=reply_info.x+(reply_info.width-scroll_info.width);
  2144.         scroll_info.y=grab_info.y-reply_info.bevel_width;
  2145.         scroll_info.raised=False;
  2146.         scroll_info.trough=True;
  2147.         north_info=scroll_info;
  2148.         north_info.raised=True;
  2149.         north_info.width-=(north_info.bevel_width << 1);
  2150.         north_info.height=north_info.width-1;
  2151.         north_info.x+=north_info.bevel_width;
  2152.         north_info.y+=north_info.bevel_width;
  2153.         south_info=north_info;
  2154.         south_info.y=scroll_info.y+scroll_info.height-scroll_info.bevel_width-
  2155.           south_info.height;
  2156.         slider_info=north_info;
  2157.         slider_info.id=0;
  2158.         slider_info.width-=2;
  2159.         slider_info.min_y=north_info.y+north_info.height+north_info.bevel_width+
  2160.           slider_info.bevel_width+2;
  2161.         slider_info.height=
  2162.           scroll_info.height-((slider_info.min_y-scroll_info.y+1) << 1)+2;
  2163.         visible_colors=
  2164.           (scroll_info.height-(height >> 3)-4)/((9*height) >> 3);
  2165.         if (colors > visible_colors)
  2166.           slider_info.height=(visible_colors*slider_info.height)/colors;
  2167.         slider_info.max_y=south_info.y-south_info.bevel_width-
  2168.           slider_info.height-slider_info.bevel_width;
  2169.         slider_info.x=scroll_info.x+slider_info.bevel_width+1;
  2170.         slider_info.y=slider_info.min_y;
  2171.         expose_info=scroll_info;
  2172.         expose_info.y=slider_info.y;
  2173.         /*
  2174.           Initialize list information.
  2175.         */
  2176.         XGetWidgetInfo((char *) NULL,&list_info);
  2177.         list_info.raised=False;
  2178.         list_info.bevel_width--;
  2179.         list_info.width=
  2180.           scroll_info.x-reply_info.x-(font_info->max_bounds.width >> 1);
  2181.         list_info.height=scroll_info.height;
  2182.         list_info.x=reply_info.x;
  2183.         list_info.y=scroll_info.y;
  2184.         /*
  2185.           Initialize text information.
  2186.         */
  2187.         XGetWidgetInfo(text,&text_info);
  2188.         text_info.width=reply_info.width;
  2189.         text_info.height=height;
  2190.         text_info.x=list_info.x-(font_info->max_bounds.width >> 1);
  2191.         text_info.y=font_info->max_bounds.width;
  2192.         /*
  2193.           Initialize selection information.
  2194.         */
  2195.         XGetWidgetInfo((char *) NULL,&selection_info);
  2196.         selection_info.width=list_info.width;
  2197.         selection_info.height=(9*height) >> 3;
  2198.         selection_info.x=list_info.x;
  2199.         state&=(~UpdateConfigurationState);
  2200.       }
  2201.     if (state & RedrawWidgetState)
  2202.       {
  2203.         /*
  2204.           Redraw color browser window.
  2205.         */
  2206.         XClearWindow(display,window->popup.id);
  2207.         x=font_info->max_bounds.width;
  2208.         y=text_info.y+((text_info.height-height) >> 1)+font_info->ascent;
  2209.         XDrawString(display,window->popup.id,window->popup.annotate_context,
  2210.           x,y,ColorPatternText,strlen(ColorPatternText));
  2211.         (void) sprintf(text_info.text,"%s",glob_pattern);
  2212.         XDrawWidgetText(display,&window->popup,&text_info);
  2213.         XDrawBeveledButton(display,&window->popup,&grab_info);
  2214.         XDrawBeveledButton(display,&window->popup,&reset_info);
  2215.         XDrawBeveledMatte(display,&window->popup,&list_info);
  2216.         XDrawBeveledMatte(display,&window->popup,&scroll_info);
  2217.         XDrawTriangleNorth(display,&window->popup,&north_info);
  2218.         XDrawBeveledButton(display,&window->popup,&slider_info);
  2219.         XDrawTriangleSouth(display,&window->popup,&south_info);
  2220.         x=font_info->max_bounds.width;
  2221.         y=reply_info.y+((reply_info.height-height) >> 1)+font_info->ascent;
  2222.         XDrawString(display,window->popup.id,window->popup.annotate_context,
  2223.           x,y,ColornameText,strlen(ColornameText));
  2224.         XDrawBeveledMatte(display,&window->popup,&reply_info);
  2225.         XDrawMatteText(display,&window->popup,&reply_info);
  2226.         XDrawBeveledButton(display,&window->popup,&action_info);
  2227.         XDrawBeveledButton(display,&window->popup,&cancel_info);
  2228.         XHighlightWidget(display,&window->popup,4,4);
  2229.         selection_info.id=(~0);
  2230.         state|=RedrawActionState;
  2231.         state|=RedrawListState;
  2232.         state&=(~RedrawWidgetState);
  2233.       }
  2234.     if (state & UpdateListState)
  2235.       {
  2236.         char
  2237.           **checklist;
  2238.  
  2239.         int
  2240.           number_colors;
  2241.  
  2242.         status=XParseColor(display,window->popup.map_info->colormap,
  2243.           glob_pattern,&color);
  2244.         if (status != 0)
  2245.           {
  2246.             /*
  2247.               Reply is a single color name-- exit.
  2248.             */
  2249.             (void) strcpy(reply,glob_pattern);
  2250.             (void) strcpy(glob_pattern,reset_pattern);
  2251.             action_info.raised=False;
  2252.             XDrawBeveledButton(display,&window->popup,&action_info);
  2253.             break;
  2254.           }
  2255.         /*
  2256.           Update color list.
  2257.         */
  2258.         checklist=XListColors(glob_pattern,&number_colors);
  2259.         if (number_colors == 0)
  2260.           {
  2261.             (void) strcpy(glob_pattern,reset_pattern);
  2262.             XBell(display,0);
  2263.           }
  2264.         else
  2265.           {
  2266.             for (i=0; i < colors; i++)
  2267.               (void) free((char *) colorlist[i]);
  2268.             if (colorlist != (char **) NULL)
  2269.               (void) free((char *) colorlist);
  2270.             colorlist=checklist;
  2271.             colors=number_colors;
  2272.           }
  2273.         /*
  2274.           Sort color list in ascending order.
  2275.         */
  2276.         slider_info.height=
  2277.           scroll_info.height-((slider_info.min_y-scroll_info.y+1) << 1)+1;
  2278.         if (colors > visible_colors)
  2279.           slider_info.height=(visible_colors*slider_info.height)/colors;
  2280.         slider_info.max_y=south_info.y-south_info.bevel_width-
  2281.           slider_info.height-slider_info.bevel_width-1;
  2282.         slider_info.id=0;
  2283.         slider_info.y=slider_info.min_y;
  2284.         expose_info.y=slider_info.y;
  2285.         selection_info.id=(~0);
  2286.         list_info.id=(~0);
  2287.         state|=RedrawListState;
  2288.         /*
  2289.           Redraw color name & reply.
  2290.         */
  2291.         *reply_info.text='\0';
  2292.         reply_info.cursor=reply_info.text;
  2293.         (void) sprintf(text_info.text,"%s",glob_pattern);
  2294.         XDrawWidgetText(display,&window->popup,&text_info);
  2295.         XDrawMatteText(display,&window->popup,&reply_info);
  2296.         XDrawBeveledMatte(display,&window->popup,&scroll_info);
  2297.         XDrawTriangleNorth(display,&window->popup,&north_info);
  2298.         XDrawBeveledButton(display,&window->popup,&slider_info);
  2299.         XDrawTriangleSouth(display,&window->popup,&south_info);
  2300.         XHighlightWidget(display,&window->popup,4,4);
  2301.         state&=(~UpdateListState);
  2302.       }
  2303.     if (state & RedrawListState)
  2304.       {
  2305.         /*
  2306.           Determine slider id and position.
  2307.         */
  2308.         if (slider_info.id >= colors)
  2309.           slider_info.id=colors-1;
  2310.         if ((slider_info.id < 0) || (colors <= visible_colors))
  2311.           slider_info.id=0;
  2312.         slider_info.y=slider_info.min_y;
  2313.         if (colors > 0)
  2314.           slider_info.y+=
  2315.             slider_info.id*(slider_info.max_y-slider_info.min_y+1)/colors;
  2316.         if (slider_info.id != selection_info.id)
  2317.           {
  2318.             /*
  2319.               Redraw scroll bar and file names.
  2320.             */
  2321.             selection_info.id=slider_info.id;
  2322.             selection_info.y=list_info.y+(height >> 3)+2;
  2323.             for (i=0; i < visible_colors; i++)
  2324.             {
  2325.               selection_info.raised=(slider_info.id+i) != list_info.id;
  2326.               selection_info.text=(char *) NULL;
  2327.               if ((slider_info.id+i) < colors)
  2328.                 selection_info.text=colorlist[slider_info.id+i];
  2329.               XDrawWidgetText(display,&window->popup,&selection_info);
  2330.               selection_info.y+=(int) selection_info.height;
  2331.             }
  2332.             /*
  2333.               Update slider.
  2334.             */
  2335.             if (slider_info.y > expose_info.y)
  2336.               {
  2337.                 expose_info.height=slider_info.y-expose_info.y;
  2338.                 expose_info.y=slider_info.y-expose_info.height-
  2339.                   slider_info.bevel_width-1;
  2340.               }
  2341.             else
  2342.               {
  2343.                 expose_info.height=expose_info.y-slider_info.y;
  2344.                 expose_info.y=slider_info.y+slider_info.height+
  2345.                   slider_info.bevel_width+1;
  2346.               }
  2347.             XDrawTriangleNorth(display,&window->popup,&north_info);
  2348.             XDrawMatte(display,&window->popup,&expose_info);
  2349.             XDrawBeveledButton(display,&window->popup,&slider_info);
  2350.             XDrawTriangleSouth(display,&window->popup,&south_info);
  2351.             expose_info.y=slider_info.y;
  2352.           }
  2353.         state&=(~RedrawListState);
  2354.       }
  2355.     if (state & RedrawActionState)
  2356.       {
  2357.         /*
  2358.           Display the selected color in a drawing area.
  2359.         */
  2360.         color=window->popup.pixel_info->matte_color;
  2361.         (void) XParseColor(display,window->popup.map_info->colormap,
  2362.           reply_info.text,&window->popup.pixel_info->matte_color);
  2363.         XBestPixel(display,window->popup.map_info->colormap,(XColor *) NULL,
  2364.           (unsigned int) window->popup.visual_info->colormap_size,
  2365.           &window->popup.pixel_info->matte_color);
  2366.         XDrawBeveledButton(display,&window->popup,&mode_info);
  2367.         window->popup.pixel_info->matte_color=color;
  2368.         state&=(~RedrawActionState);
  2369.       }
  2370.   } while (!(state & ExitState));
  2371.   XDefineCursor(display,window->image.id,window->image.cursor);
  2372.   XWithdrawWindow(display,window->popup.id,window->popup.screen);
  2373.   XDelay(display,SuspendTime << 2);
  2374.   while (XCheckTypedWindowEvent(display,window->image.id,Expose,&event))
  2375.     XRefreshWindow(display,&window->image,&event);
  2376.   /*
  2377.     Free color list.
  2378.   */
  2379.   for (i=0; i < colors; i++)
  2380.     (void) free((char *) colorlist[i]);
  2381.   if (colorlist != (char **) NULL)
  2382.     (void) free((char *) colorlist);
  2383. }
  2384.  
  2385. /*
  2386. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  2387. %                                                                             %
  2388. %                                                                             %
  2389. %                                                                             %
  2390. %   X D i a l o g W i d g e t                                                 %
  2391. %                                                                             %
  2392. %                                                                             %
  2393. %                                                                             %
  2394. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  2395. %
  2396. %  Function XDialogWidget displays a popup window with a query to the user.
  2397. %  The user keys a reply and presses the Ok or Cancel button to exit.  The
  2398. %  typed text is returned as the reply function parameter.
  2399. %
  2400. %  The format of the XDialogWidget routine is:
  2401. %
  2402. %    XDialogWidget(display,resource_info,window,action,query,reply)
  2403. %
  2404. %  A description of each parameter follows:
  2405. %
  2406. %    o display: Specifies a connection to an X server;  returned from
  2407. %      XOpenDisplay.
  2408. %
  2409. %    o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
  2410. %
  2411. %    o window: Specifies a pointer to a XWindows structure.
  2412. %
  2413. %    o action: Specifies a pointer to the action of this widget.
  2414. %
  2415. %    o query: Specifies a pointer to the query to present to the user.
  2416. %
  2417. %    o reply: The response from the user is returned in this parameter.
  2418. %
  2419. %
  2420. */
  2421. void XDialogWidget(display,resource_info,window,action,query,reply)
  2422. Display
  2423.   *display;
  2424.  
  2425. XResourceInfo
  2426.   *resource_info;
  2427.  
  2428. XWindows
  2429.   *window;
  2430.  
  2431. char
  2432.   *action,
  2433.   *query,
  2434.   *reply;
  2435. {
  2436. #define CancelButtonText  "Cancel"
  2437.  
  2438.   char
  2439.     primary_selection[MaxTextLength];
  2440.  
  2441.   int
  2442.     x,
  2443.     x_offset,
  2444.     y,
  2445.     y_offset;
  2446.  
  2447.   register int
  2448.     i;
  2449.  
  2450.   unsigned int
  2451.     height,
  2452.     limit,
  2453.     mask,
  2454.     width;
  2455.  
  2456.   unsigned long
  2457.     state;
  2458.  
  2459.   Window
  2460.     child,
  2461.     root_window;
  2462.  
  2463.   XEvent
  2464.     event;
  2465.  
  2466.   XFontStruct
  2467.     *font_info;
  2468.  
  2469.   XTextProperty
  2470.     window_name;
  2471.  
  2472.   XWidgetInfo
  2473.     action_info,
  2474.     cancel_info,
  2475.     reply_info,
  2476.     text_info;
  2477.  
  2478.   XWindowChanges
  2479.     window_changes;
  2480.  
  2481.   /*
  2482.     Determine popup window attributes.
  2483.   */
  2484.   font_info=window->popup.font_info;
  2485.   width=XTextWidth(font_info,action,strlen(action));
  2486.   if (XTextWidth(font_info,CancelButtonText,strlen(CancelButtonText)) > width)
  2487.     width=XTextWidth(font_info,CancelButtonText,strlen(CancelButtonText));
  2488.   width+=(3*font_info->max_bounds.width) >> 1;
  2489.   height=font_info->ascent+font_info->descent;
  2490.   window->popup.width=Max(width,XTextWidth(font_info,query,strlen(query)))+
  2491.     6*font_info->max_bounds.width;
  2492.   window->popup.height=7*height+(font_info->max_bounds.width << 1);
  2493.   window->popup.min_width=width+25*XTextWidth(font_info,"#",1)+
  2494.     4*font_info->max_bounds.width;
  2495.   window->popup.min_height=window->popup.height;
  2496.   /*
  2497.     Position popup window.
  2498.   */
  2499.   XQueryPointer(display,XRootWindow(display,window->popup.screen),&root_window,
  2500.     &root_window,&x,&y,&window->popup.x,&window->popup.y,&mask);
  2501.   if (window->popup.width < window->popup.min_width)
  2502.     window->popup.width=window->popup.min_width;
  2503.   window->popup.x-=(window->popup.width >> 1);
  2504.   limit=XDisplayWidth(display,window->popup.screen)-window->popup.width;
  2505.   if (window->popup.x < 0)
  2506.     window->popup.x=0;
  2507.   else
  2508.     if (window->popup.x > limit)
  2509.       window->popup.x=limit;
  2510.   if (window->popup.height < window->popup.min_height)
  2511.     window->popup.height=window->popup.min_height;
  2512.   window->popup.y-=(window->popup.height >> 1);
  2513.   limit=XDisplayHeight(display,window->popup.screen)-window->popup.height;
  2514.   if (window->popup.y < 0)
  2515.     window->popup.y=0;
  2516.   else
  2517.     if (window->popup.y > limit)
  2518.       window->popup.y=limit;
  2519.   /*
  2520.     Map popup window.
  2521.   */
  2522.   (void) sprintf(window->popup.name,"Dialog");
  2523.   (void) XStringListToTextProperty(&window->popup.name,1,&window_name);
  2524.   XSetWMName(display,window->popup.id,&window_name);
  2525.   window_changes.width=window->popup.width;
  2526.   window_changes.height=window->popup.height;
  2527.   window_changes.x=window->popup.x;
  2528.   window_changes.y=window->popup.y;
  2529.   XReconfigureWMWindow(display,window->popup.id,window->popup.screen,CWWidth |
  2530.     CWHeight | CWX | CWY,&window_changes);
  2531.   XMapRaised(display,window->popup.id);
  2532.   /*
  2533.     Respond to X events.
  2534.   */
  2535.   state=UpdateConfigurationState;
  2536.   XDefineCursor(display,window->image.id,window->image.busy_cursor);
  2537.   do
  2538.   {
  2539.     /*
  2540.       Wait for next event.
  2541.     */
  2542.     XIfEvent(display,&event,XWidgetEvent,(char *) window);
  2543.     switch (event.type)
  2544.     {
  2545.       case ButtonPress:
  2546.       {
  2547.         if (event.xbutton.window != window->popup.id)
  2548.           {
  2549.             XBell(display,0);
  2550.             break;
  2551.           }
  2552.         if (MatteIsActive(action_info,event.xbutton))
  2553.           {
  2554.             /*
  2555.               User pressed Action button.
  2556.             */
  2557.             action_info.raised=False;
  2558.             XDrawBeveledButton(display,&window->popup,&action_info);
  2559.             break;
  2560.           }
  2561.         if (MatteIsActive(cancel_info,event.xbutton))
  2562.           {
  2563.             /*
  2564.               User pressed Cancel button.
  2565.             */
  2566.             cancel_info.raised=False;
  2567.             XDrawBeveledButton(display,&window->popup,&cancel_info);
  2568.             break;
  2569.           }
  2570.         if ((event.xbutton.button == Button3) &&
  2571.             (event.xbutton.state & Mod1Mask))
  2572.           {
  2573.             /*
  2574.               Convert Alt-Matte3 to Button2.
  2575.             */
  2576.             event.xbutton.button=Button2;
  2577.             event.xbutton.state&=(~Mod1Mask);
  2578.           }
  2579.         if (!MatteIsActive(reply_info,event.xbutton))
  2580.           break;
  2581.         if (event.xbutton.button != Button2)
  2582.           {
  2583.             static Time
  2584.               click_time;
  2585.  
  2586.             /*
  2587.               Move text cursor to position of button press.
  2588.             */
  2589.             x=event.xbutton.x-reply_info.x-(font_info->max_bounds.width >> 2);
  2590.             for (i=1; i <= (int) strlen(reply_info.marker); i++)
  2591.               if (XTextWidth(font_info,reply_info.marker,i) > x)
  2592.                 break;
  2593.             reply_info.cursor=reply_info.marker+i-1;
  2594.             if (event.xbutton.time < (click_time+DoubleClick))
  2595.               {
  2596.                 /*
  2597.                   Become the XA_PRIMARY selection owner.
  2598.                 */
  2599.                 (void) strcpy(primary_selection,reply_info.text);
  2600.                 XSetSelectionOwner(display,XA_PRIMARY,window->popup.id,
  2601.                   event.xbutton.time);
  2602.                 reply_info.highlight=XGetSelectionOwner(display,XA_PRIMARY) ==
  2603.                   window->popup.id;
  2604.               }
  2605.             XDrawMatteText(display,&window->popup,&reply_info);
  2606.             click_time=event.xbutton.time;
  2607.             break;
  2608.           }
  2609.         /*
  2610.           Request primary selection.
  2611.         */
  2612.         XConvertSelection(display,XA_PRIMARY,XA_STRING,XA_STRING,
  2613.           window->popup.id,event.xbutton.time);
  2614.         break;
  2615.       }
  2616.       case ButtonRelease:
  2617.       {
  2618.         if (!action_info.raised)
  2619.           {
  2620.             if (event.xbutton.window == window->popup.id)
  2621.               if (MatteIsActive(action_info,event.xbutton))
  2622.                 if (*reply_info.text == '\0')
  2623.                   XBell(display,0);
  2624.                 else
  2625.                   state|=ExitState;
  2626.             action_info.raised=True;
  2627.             XDrawBeveledButton(display,&window->popup,&action_info);
  2628.           }
  2629.         if (!cancel_info.raised)
  2630.           {
  2631.             if (event.xbutton.window == window->popup.id)
  2632.               if (MatteIsActive(cancel_info,event.xbutton))
  2633.                 {
  2634.                   *reply_info.text='\0';
  2635.                   state|=ExitState;
  2636.                 }
  2637.             cancel_info.raised=True;
  2638.             XDrawBeveledButton(display,&window->popup,&cancel_info);
  2639.           }
  2640.         break;
  2641.       }
  2642.       case ConfigureNotify:
  2643.       {
  2644.         /*
  2645.           Update widget configuration.
  2646.         */
  2647.         if (event.xconfigure.window != window->popup.id)
  2648.           break;
  2649.         if ((window->popup.width != event.xconfigure.width) ||
  2650.             (window->popup.height != event.xconfigure.height))
  2651.           state|=RedrawWidgetState;
  2652.         window->popup.width=Max(event.xconfigure.width,window->popup.min_width);
  2653.         window->popup.height=
  2654.           Max(event.xconfigure.height,window->popup.min_height);
  2655.         state|=UpdateConfigurationState;
  2656.         break;
  2657.       }
  2658.       case Expose:
  2659.       {
  2660.         if (event.xexpose.window == window->image.id)
  2661.           {
  2662.             XRefreshWindow(display,&window->image,&event);
  2663.             break;
  2664.           }
  2665.         if (event.xexpose.window == window->magnify.id)
  2666.           if (event.xexpose.count == 0)
  2667.             if (window->magnify.mapped)
  2668.               {
  2669.                 XMakeMagnifyImage(display,resource_info,window);
  2670.                 break;
  2671.               }
  2672.         if (event.xexpose.window != window->popup.id)
  2673.           break;
  2674.         if (event.xexpose.count != 0)
  2675.           break;
  2676.         state|=RedrawWidgetState;
  2677.         break;
  2678.       }
  2679.       case KeyPress:
  2680.       {
  2681.         static char
  2682.           command[MaxTextLength];
  2683.  
  2684.         static int
  2685.           length;
  2686.  
  2687.         static KeySym
  2688.           key_symbol;
  2689.  
  2690.         if (event.xkey.window != window->popup.id)
  2691.           break;
  2692.         /*
  2693.           Respond to a user key press.
  2694.         */
  2695.         length=XLookupString((XKeyEvent *) &event.xkey,command,sizeof(command),
  2696.           &key_symbol,(XComposeStatus *) NULL);
  2697.         *(command+length)='\0';
  2698.         if (!MatteIsActive(reply_info,event.xkey))
  2699.           break;
  2700.         if ((key_symbol == XK_Return) || (key_symbol == XK_KP_Enter))
  2701.           {
  2702.             if (*reply_info.text != '\0')
  2703.               state|=ExitState;
  2704.             break;
  2705.           }
  2706.         if (key_symbol == XK_Control_L)
  2707.           {
  2708.             state|=ControlState;
  2709.             break;
  2710.           }
  2711.         if (state & ControlState)
  2712.           switch (key_symbol)
  2713.           {
  2714.             case XK_u:
  2715.             case XK_U:
  2716.             {
  2717.               key_symbol=XK_Delete;
  2718.               break;
  2719.             }
  2720.             default:
  2721.               break;
  2722.           }
  2723.         XEditText(display,&reply_info,key_symbol,command,state);
  2724.         XDrawMatteText(display,&window->popup,&reply_info);
  2725.         break;
  2726.       }
  2727.       case KeyRelease:
  2728.       {
  2729.         static char
  2730.           command[MaxTextLength];
  2731.  
  2732.         static KeySym
  2733.           key_symbol;
  2734.  
  2735.         if (event.xkey.window != window->popup.id)
  2736.           break;
  2737.         /*
  2738.           Respond to a user key release.
  2739.         */
  2740.         (void) XLookupString((XKeyEvent *) &event.xkey,command,sizeof(command),
  2741.           &key_symbol,(XComposeStatus *) NULL);
  2742.         if (key_symbol == XK_Control_L)
  2743.           state&=(~ControlState);
  2744.         break;
  2745.       }
  2746.       case MotionNotify:
  2747.       {
  2748.         /*
  2749.           Discard pending button motion events.
  2750.         */
  2751.         while (XCheckMaskEvent(display,ButtonMotionMask,&event));
  2752.         if (event.xmotion.window == window->image.id)
  2753.           {
  2754.             XTranslateCoordinates(display,event.xmotion.window,window->popup.id,
  2755.               0,0,&x_offset,&y_offset,&child);
  2756.             event.xmotion.x+=x_offset;
  2757.             event.xmotion.y+=y_offset;
  2758.           }
  2759.         if (action_info.raised == MatteIsActive(action_info,event.xmotion))
  2760.           {
  2761.             /*
  2762.               Action button status changed.
  2763.             */
  2764.             action_info.raised=!action_info.raised;
  2765.             XDrawBeveledButton(display,&window->popup,&action_info);
  2766.             break;
  2767.           }
  2768.         if (cancel_info.raised == MatteIsActive(cancel_info,event.xmotion))
  2769.           {
  2770.             /*
  2771.               Cancel button status changed.
  2772.             */
  2773.             cancel_info.raised=!cancel_info.raised;
  2774.             XDrawBeveledButton(display,&window->popup,&cancel_info);
  2775.             break;
  2776.           }
  2777.         break;
  2778.       }
  2779.       case SelectionClear:
  2780.       {
  2781.         reply_info.highlight=False;
  2782.         XDrawMatteText(display,&window->popup,&reply_info);
  2783.         break;
  2784.       }
  2785.       case SelectionNotify:
  2786.       {
  2787.         Atom
  2788.           type;
  2789.  
  2790.         int
  2791.           format,
  2792.           status;
  2793.  
  2794.         unsigned char
  2795.           *data;
  2796.  
  2797.         unsigned long
  2798.           after,
  2799.           length;
  2800.  
  2801.         /*
  2802.           Obtain response from primary selection.
  2803.         */
  2804.         if (event.xselection.property == (Atom) None)
  2805.           break;
  2806.         status=XGetWindowProperty(display,event.xselection.requestor,
  2807.           event.xselection.property,0L,2047L,True,XA_STRING,&type,&format,
  2808.           &length,&after,&data);
  2809.         if ((status != Success) || (type != XA_STRING) || (format == 32) ||
  2810.             (length == 0))
  2811.           break;
  2812.         if ((strlen(reply_info.text)+length) >= MaxTextLength)
  2813.           XBell(display,0);
  2814.         else
  2815.           {
  2816.             /*
  2817.               Insert primary selection in reply text.
  2818.             */
  2819.             *(data+length)='\0';
  2820.             XEditText(display,&reply_info,(KeySym) XK_Insert,(char *) data,
  2821.               state);
  2822.             XDrawMatteText(display,&window->popup,&reply_info);
  2823.           }
  2824.         XFree((void *) data);
  2825.         break;
  2826.       }
  2827.       case SelectionRequest:
  2828.       {
  2829.         XSelectionEvent
  2830.           notify;
  2831.  
  2832.         XSelectionRequestEvent
  2833.           *request;
  2834.  
  2835.         if (!reply_info.highlight)
  2836.           break;
  2837.         /*
  2838.           Set primary selection.
  2839.         */
  2840.         request=(&(event.xselectionrequest));
  2841.         XChangeProperty(request->display,request->requestor,request->property,
  2842.           request->target,8,PropModeReplace,primary_selection,
  2843.           strlen(primary_selection));
  2844.         notify.type=SelectionNotify;
  2845.         notify.display=request->display;
  2846.         notify.requestor=request->requestor;
  2847.         notify.selection=request->selection;
  2848.         notify.target=request->target;
  2849.         notify.time=request->time;
  2850.         if (request->property == None)
  2851.           notify.property=request->target;
  2852.         else
  2853.           notify.property=request->property;
  2854.         (void) XSendEvent(request->display,request->requestor,False,0,
  2855.           (XEvent *) ¬ify);
  2856.       }
  2857.       default:
  2858.         break;
  2859.     }
  2860.     if (state & UpdateConfigurationState)
  2861.       {
  2862.         /*
  2863.           Initialize button information.
  2864.         */
  2865.         XGetWidgetInfo(CancelButtonText,&cancel_info);
  2866.         cancel_info.width=width;
  2867.         cancel_info.height=(3*height) >> 1;
  2868.         cancel_info.x=window->popup.width-cancel_info.width-
  2869.           ((3*font_info->max_bounds.width) >> 1);
  2870.         cancel_info.y=window->popup.height-cancel_info.height-
  2871.           ((3*font_info->max_bounds.width) >> 1);
  2872.         XGetWidgetInfo(action,&action_info);
  2873.         action_info.width=width;
  2874.         action_info.height=(3*height) >> 1;
  2875.         action_info.x=cancel_info.x-(cancel_info.width+
  2876.           font_info->max_bounds.width+(action_info.bevel_width << 1));
  2877.         action_info.y=cancel_info.y;
  2878.         /*
  2879.           Initialize reply information.
  2880.         */
  2881.         XGetWidgetInfo(reply,&reply_info);
  2882.         reply_info.raised=False;
  2883.         reply_info.bevel_width--;
  2884.         reply_info.width=window->popup.width-(3*font_info->max_bounds.width);
  2885.         reply_info.height=height << 1;
  2886.         reply_info.x=(3*font_info->max_bounds.width) >> 1;
  2887.         reply_info.y=action_info.y-reply_info.height-
  2888.           font_info->max_bounds.width;
  2889.         /*
  2890.           Initialize text information.
  2891.         */
  2892.         XGetWidgetInfo(query,&text_info);
  2893.         text_info.width=reply_info.width;
  2894.         text_info.height=height;
  2895.         text_info.x=reply_info.x-(font_info->max_bounds.width >> 1);
  2896.         text_info.y=font_info->max_bounds.width;
  2897.         state&=(~UpdateConfigurationState);
  2898.       }
  2899.     if (state & RedrawWidgetState)
  2900.       {
  2901.         /*
  2902.           Redraw Dialog widget.
  2903.         */
  2904.         XClearWindow(display,window->popup.id);
  2905.         XDrawWidgetText(display,&window->popup,&text_info);
  2906.         XDrawBeveledMatte(display,&window->popup,&reply_info);
  2907.         XDrawMatteText(display,&window->popup,&reply_info);
  2908.         XDrawBeveledButton(display,&window->popup,&action_info);
  2909.         XDrawBeveledButton(display,&window->popup,&cancel_info);
  2910.         XHighlightWidget(display,&window->popup,4,4);
  2911.         state&=(~RedrawWidgetState);
  2912.       }
  2913.   } while (!(state & ExitState));
  2914.   XDefineCursor(display,window->image.id,window->image.cursor);
  2915.   XWithdrawWindow(display,window->popup.id,window->popup.screen);
  2916.   XDelay(display,SuspendTime << 2);
  2917.   while (XCheckTypedWindowEvent(display,window->image.id,Expose,&event))
  2918.     XRefreshWindow(display,&window->image,&event);
  2919. }
  2920.  
  2921. /*
  2922. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  2923. %                                                                             %
  2924. %                                                                             %
  2925. %                                                                             %
  2926. %   X F i l e B r o w s e r W i d g e t                                       %
  2927. %                                                                             %
  2928. %                                                                             %
  2929. %                                                                             %
  2930. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  2931. %
  2932. %  Function XFileBrowserWidget displays a popup window with a file query to
  2933. %  the user.  The user keys a reply and presses the Action or Cancel button
  2934. %  to exit.  The typed text is returned as the reply function parameter.
  2935. %
  2936. %  The format of the XFileBrowserWidget routine is:
  2937. %
  2938. %    XFileBrowserWidget(display,resource_info,window,action,reply)
  2939. %
  2940. %  A description of each parameter follows:
  2941. %
  2942. %    o display: Specifies a connection to an X server;  returned from
  2943. %      XOpenDisplay.
  2944. %
  2945. %    o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
  2946. %
  2947. %    o window: Specifies a pointer to a XWindows structure.
  2948. %
  2949. %    o action: Specifies a pointer to the action of this widget.
  2950. %
  2951. %    o reply: The response from the user is returned in this parameter.
  2952. %
  2953. %
  2954. */
  2955. void XFileBrowserWidget(display,resource_info,window,action,reply)
  2956. Display
  2957.   *display;
  2958.  
  2959. XResourceInfo
  2960.   *resource_info;
  2961.  
  2962. XWindows
  2963.   *window;
  2964.  
  2965. char
  2966.   *action,
  2967.   *reply;
  2968. {
  2969. #define CancelButtonText  "Cancel"
  2970. #define DirectoryText  "Directory:"
  2971. #define FilenameText  "File name:"
  2972. #define HomeButtonText  "Home"
  2973. #define UpButtonText  "Up"
  2974.  
  2975.   char
  2976.     **filelist,
  2977.     home_directory[MaxTextLength],
  2978.     primary_selection[MaxTextLength],
  2979.     text[MaxTextLength],
  2980.     working_directory[MaxTextLength];
  2981.  
  2982.   int
  2983.     files,
  2984.     x,
  2985.     x_offset,
  2986.     y,
  2987.     y_offset;
  2988.  
  2989.   register int
  2990.     i;
  2991.  
  2992.   static char
  2993.     glob_pattern[MaxTextLength] = "*";
  2994.  
  2995.   unsigned int
  2996.     delay,
  2997.     height,
  2998.     limit,
  2999.     mask,
  3000.     text_width,
  3001.     visible_filenames,
  3002.     width;
  3003.  
  3004.   unsigned long
  3005.     state;
  3006.  
  3007.   Window
  3008.     child,
  3009.     root_window;
  3010.  
  3011.   XEvent
  3012.     event;
  3013.  
  3014.   XFontStruct
  3015.     *font_info;
  3016.  
  3017.   XTextProperty
  3018.     window_name;
  3019.  
  3020.   XWidgetInfo
  3021.     action_info,
  3022.     cancel_info,
  3023.     expose_info,
  3024.     list_info,
  3025.     home_info,
  3026.     north_info,
  3027.     reply_info,
  3028.     scroll_info,
  3029.     selection_info,
  3030.     slider_info,
  3031.     south_info,
  3032.     text_info,
  3033.     up_info;
  3034.  
  3035.   XWindowChanges
  3036.     window_changes;
  3037.  
  3038.   /*
  3039.     Read filelist from current directory.
  3040.   */
  3041.   XDefineCursor(display,window->image.id,window->image.busy_cursor);
  3042.   XFlush(display);
  3043.   (void) getcwd(home_directory,MaxTextLength-1);
  3044.   (void) strcpy(working_directory,home_directory);
  3045.   filelist=ListFiles(working_directory,glob_pattern,&files);
  3046.   if (filelist == (char **) NULL)
  3047.     {
  3048.       /*
  3049.         Directory read failed.
  3050.       */
  3051.       XNoticeWidget(display,resource_info,window,"Unable to read directory",
  3052.         working_directory);
  3053.       return;
  3054.     }
  3055.   /*
  3056.     Determine popup window attributes.
  3057.   */
  3058.   font_info=window->popup.font_info;
  3059.   text_width=0;
  3060.   for (i=0; i < files; i++)
  3061.     if (XTextWidth(font_info,filelist[i],strlen(filelist[i])) > text_width)
  3062.       text_width=XTextWidth(font_info,filelist[i],strlen(filelist[i]));
  3063.   width=XTextWidth(font_info,action,strlen(action));
  3064.   if (XTextWidth(font_info,CancelButtonText,strlen(CancelButtonText)) > width)
  3065.     width=XTextWidth(font_info,CancelButtonText,strlen(CancelButtonText));
  3066.   if (XTextWidth(font_info,HomeButtonText,strlen(HomeButtonText)) > width)
  3067.     width=XTextWidth(font_info,HomeButtonText,strlen(HomeButtonText));
  3068.   if (XTextWidth(font_info,UpButtonText,strlen(UpButtonText)) > width)
  3069.     width=XTextWidth(font_info,UpButtonText,strlen(UpButtonText));
  3070.   width+=font_info->max_bounds.width;
  3071.   if (XTextWidth(font_info,DirectoryText,strlen(DirectoryText)) > width)
  3072.     width=XTextWidth(font_info,DirectoryText,strlen(DirectoryText));
  3073.   if (XTextWidth(font_info,FilenameText,strlen(FilenameText)) > width)
  3074.     width=XTextWidth(font_info,FilenameText,strlen(FilenameText));
  3075.   height=font_info->ascent+font_info->descent;
  3076.   window->popup.width=width+text_width+6*font_info->max_bounds.width;
  3077.   window->popup.height=
  3078.     ((81*height) >> 2)+((13*font_info->max_bounds.width) >> 1)+4;
  3079.   window->popup.min_width=width+25*XTextWidth(font_info,"#",1)+
  3080.     4*font_info->max_bounds.width;
  3081.   window->popup.min_height=
  3082.     ((23*height) >> 1)+((13*font_info->max_bounds.width) >> 1)+4;
  3083.   /*
  3084.     Position popup window.
  3085.   */
  3086.   XQueryPointer(display,XRootWindow(display,window->popup.screen),&root_window,
  3087.     &root_window,&x,&y,&window->popup.x,&window->popup.y,&mask);
  3088.   if (window->popup.width < window->popup.min_width)
  3089.     window->popup.width=window->popup.min_width;
  3090.   window->popup.x-=((3*window->popup.width) >> 2);
  3091.   limit=XDisplayWidth(display,window->popup.screen)-window->popup.width;
  3092.   if (window->popup.x < 0)
  3093.     window->popup.x=0;
  3094.   else
  3095.     if (window->popup.x > limit)
  3096.       window->popup.x=limit;
  3097.   if (window->popup.height < window->popup.min_height)
  3098.     window->popup.height=window->popup.min_height;
  3099.   window->popup.y-=(window->popup.height >> 1);
  3100.   limit=XDisplayHeight(display,window->popup.screen)-window->popup.height;
  3101.   if (window->popup.y < 0)
  3102.     window->popup.y=0;
  3103.   else
  3104.     if (window->popup.y > limit)
  3105.       window->popup.y=limit;
  3106.   /*
  3107.     Map popup window.
  3108.   */
  3109.   (void) sprintf(window->popup.name,"Browse and Select a File");
  3110.   (void) XStringListToTextProperty(&window->popup.name,1,&window_name);
  3111.   XSetWMName(display,window->popup.id,&window_name);
  3112.   window_changes.width=window->popup.width;
  3113.   window_changes.height=window->popup.height;
  3114.   window_changes.x=window->popup.x;
  3115.   window_changes.y=window->popup.y;
  3116.   XReconfigureWMWindow(display,window->popup.id,window->popup.screen,CWWidth |
  3117.     CWHeight | CWX | CWY,&window_changes);
  3118.   XMapRaised(display,window->popup.id);
  3119.   /*
  3120.     Respond to X events.
  3121.   */
  3122.   XGetWidgetInfo((char *) NULL,&north_info);
  3123.   XGetWidgetInfo((char *) NULL,&south_info);
  3124.   visible_filenames=0;
  3125.   delay=SuspendTime << 2;
  3126.   state=UpdateConfigurationState;
  3127.   do
  3128.   {
  3129.     /*
  3130.       Wait for next event.
  3131.     */
  3132.     if (north_info.raised && south_info.raised)
  3133.       XIfEvent(display,&event,XWidgetEvent,(char *) window);
  3134.     else
  3135.       {
  3136.         /*
  3137.           Brief delay before advancing scroll bar.
  3138.         */
  3139.         XDelay(display,delay);
  3140.         XCheckMaskEvent(display,ButtonReleaseMask,&event);
  3141.         delay=SuspendTime;
  3142.       }
  3143.     switch (event.type)
  3144.     {
  3145.       case ButtonPress:
  3146.       {
  3147.         if (event.xbutton.window != window->popup.id)
  3148.           {
  3149.             XBell(display,0);
  3150.             break;
  3151.           }
  3152.         if (MatteIsActive(slider_info,event.xbutton))
  3153.           {
  3154.             /*
  3155.               Track slider.
  3156.             */
  3157.             slider_info.active=True;
  3158.             break;
  3159.           }
  3160.         if (MatteIsActive(north_info,event.xbutton))
  3161.           if (slider_info.id > 0)
  3162.             {
  3163.               /*
  3164.                 Move slider up.
  3165.               */
  3166.               north_info.raised=False;
  3167.               slider_info.id--;
  3168.               state|=RedrawListState;
  3169.               break;
  3170.             }
  3171.         if (MatteIsActive(south_info,event.xbutton))
  3172.           if (slider_info.id < files)
  3173.             {
  3174.               /*
  3175.                 Move slider down.
  3176.               */
  3177.               south_info.raised=False;
  3178.               slider_info.id++;
  3179.               state|=RedrawListState;
  3180.               break;
  3181.             }
  3182.         if (MatteIsActive(scroll_info,event.xbutton))
  3183.           {
  3184.             /*
  3185.               Move slider.
  3186.             */
  3187.             if (event.xbutton.y < slider_info.y)
  3188.               slider_info.id-=(visible_filenames-1);
  3189.             else
  3190.               slider_info.id+=(visible_filenames-1);
  3191.             state|=RedrawListState;
  3192.             break;
  3193.           }
  3194.         if (MatteIsActive(list_info,event.xbutton))
  3195.           {
  3196.             unsigned int
  3197.               id;
  3198.  
  3199.             /*
  3200.               User pressed file matte.
  3201.             */
  3202.             id=slider_info.id+(event.xbutton.y-(list_info.y+(height >> 1))+1)/
  3203.               selection_info.height;
  3204.             if (id >= files)
  3205.               break;
  3206.             (void) strcpy(reply_info.text,filelist[id]);
  3207.             reply_info.highlight=False;
  3208.             reply_info.marker=reply_info.text;
  3209.             reply_info.cursor=reply_info.text+strlen(reply_info.text);
  3210.             XDrawMatteText(display,&window->popup,&reply_info);
  3211.             if (id == list_info.id)
  3212.               {
  3213.                 (void) strcpy(working_directory,reply_info.text);
  3214.                 state|=UpdateListState;
  3215.               }
  3216.             selection_info.id=(~0);
  3217.             list_info.id=id;
  3218.             state|=RedrawListState;
  3219.             break;
  3220.           }
  3221.         if (MatteIsActive(up_info,event.xbutton))
  3222.           {
  3223.             /*
  3224.               User pressed Up button.
  3225.             */
  3226.             up_info.raised=False;
  3227.             XDrawBeveledButton(display,&window->popup,&up_info);
  3228.             break;
  3229.           }
  3230.         if (MatteIsActive(home_info,event.xbutton))
  3231.           {
  3232.             /*
  3233.               User pressed Home button.
  3234.             */
  3235.             home_info.raised=False;
  3236.             XDrawBeveledButton(display,&window->popup,&home_info);
  3237.             break;
  3238.           }
  3239.         if (MatteIsActive(action_info,event.xbutton))
  3240.           {
  3241.             /*
  3242.               User pressed action button.
  3243.             */
  3244.             action_info.raised=False;
  3245.             XDrawBeveledButton(display,&window->popup,&action_info);
  3246.             break;
  3247.           }
  3248.         if (MatteIsActive(cancel_info,event.xbutton))
  3249.           {
  3250.             /*
  3251.               User pressed Cancel button.
  3252.             */
  3253.             cancel_info.raised=False;
  3254.             XDrawBeveledButton(display,&window->popup,&cancel_info);
  3255.             break;
  3256.           }
  3257.         if ((event.xbutton.button == Button3) &&
  3258.             (event.xbutton.state & Mod1Mask))
  3259.           {
  3260.             /*
  3261.               Convert Alt-Matte3 to Button2.
  3262.             */
  3263.             event.xbutton.button=Button2;
  3264.             event.xbutton.state&=(~Mod1Mask);
  3265.           }
  3266.         if (!MatteIsActive(reply_info,event.xbutton))
  3267.           break;
  3268.         if (event.xbutton.button != Button2)
  3269.           {
  3270.             static Time
  3271.               click_time;
  3272.  
  3273.             /*
  3274.               Move text cursor to position of button press.
  3275.             */
  3276.             x=event.xbutton.x-reply_info.x-(font_info->max_bounds.width >> 2);
  3277.             for (i=1; i <= (int) strlen(reply_info.marker); i++)
  3278.               if (XTextWidth(font_info,reply_info.marker,i) > x)
  3279.                 break;
  3280.             reply_info.cursor=reply_info.marker+i-1;
  3281.             if (event.xbutton.time < (click_time+DoubleClick))
  3282.               {
  3283.                 /*
  3284.                   Become the XA_PRIMARY selection owner.
  3285.                 */
  3286.                 (void) strcpy(primary_selection,reply_info.text);
  3287.                 XSetSelectionOwner(display,XA_PRIMARY,window->popup.id,
  3288.                   event.xbutton.time);
  3289.                 reply_info.highlight=XGetSelectionOwner(display,XA_PRIMARY) ==
  3290.                   window->popup.id;
  3291.               }
  3292.             XDrawMatteText(display,&window->popup,&reply_info);
  3293.             click_time=event.xbutton.time;
  3294.             break;
  3295.           }
  3296.         /*
  3297.           Request primary selection.
  3298.         */
  3299.         XConvertSelection(display,XA_PRIMARY,XA_STRING,XA_STRING,
  3300.           window->popup.id,event.xbutton.time);
  3301.         break;
  3302.       }
  3303.       case ButtonRelease:
  3304.       {
  3305.         if (!north_info.raised)
  3306.           {
  3307.             /*
  3308.               User released up button.
  3309.             */
  3310.             delay=SuspendTime << 2;
  3311.             north_info.raised=True;
  3312.             XDrawTriangleNorth(display,&window->popup,&north_info);
  3313.           }
  3314.         if (!south_info.raised)
  3315.           {
  3316.             /*
  3317.               User released down button.
  3318.             */
  3319.             delay=SuspendTime << 2;
  3320.             south_info.raised=True;
  3321.             XDrawTriangleSouth(display,&window->popup,&south_info);
  3322.           }
  3323.         if (slider_info.active)
  3324.           {
  3325.             /*
  3326.               Stop tracking slider.
  3327.             */
  3328.             slider_info.active=False;
  3329.             break;
  3330.           }
  3331.         if (!up_info.raised)
  3332.           {
  3333.             if (event.xbutton.window == window->popup.id)
  3334.               if (MatteIsActive(up_info,event.xbutton))
  3335.                 {
  3336.                   (void) strcpy(working_directory,"..");
  3337.                   state|=UpdateListState;
  3338.                 }
  3339.             up_info.raised=True;
  3340.             XDrawBeveledButton(display,&window->popup,&up_info);
  3341.           }
  3342.         if (!home_info.raised)
  3343.           {
  3344.             if (event.xbutton.window == window->popup.id)
  3345.               if (MatteIsActive(home_info,event.xbutton))
  3346.                 {
  3347.                   (void) strcpy(working_directory,home_directory);
  3348.                   state|=UpdateListState;
  3349.                 }
  3350.             home_info.raised=True;
  3351.             XDrawBeveledButton(display,&window->popup,&home_info);
  3352.           }
  3353.         if (!action_info.raised)
  3354.           {
  3355.             if (event.xbutton.window == window->popup.id)
  3356.               if (MatteIsActive(action_info,event.xbutton))
  3357.                 if (*reply_info.text == '\0')
  3358.                   XBell(display,0);
  3359.                 else
  3360.                   state|=ExitState;
  3361.             action_info.raised=True;
  3362.             XDrawBeveledButton(display,&window->popup,&action_info);
  3363.           }
  3364.         if (!cancel_info.raised)
  3365.           {
  3366.             if (event.xbutton.window == window->popup.id)
  3367.               if (MatteIsActive(cancel_info,event.xbutton))
  3368.                 {
  3369.                   *reply_info.text='\0';
  3370.                   state|=ExitState;
  3371.                 }
  3372.             cancel_info.raised=True;
  3373.             XDrawBeveledButton(display,&window->popup,&cancel_info);
  3374.           }
  3375.         break;
  3376.       }
  3377.       case ConfigureNotify:
  3378.       {
  3379.         /*
  3380.           Update widget configuration.
  3381.         */
  3382.         if (event.xconfigure.window != window->popup.id)
  3383.           break;
  3384.         if ((window->popup.width != event.xconfigure.width) ||
  3385.             (window->popup.height != event.xconfigure.height))
  3386.           state|=RedrawWidgetState;
  3387.         window->popup.width=Max(event.xconfigure.width,window->popup.min_width);
  3388.         window->popup.height=
  3389.           Max(event.xconfigure.height,window->popup.min_height);
  3390.         state|=UpdateConfigurationState;
  3391.         break;
  3392.       }
  3393.       case Expose:
  3394.       {
  3395.         if (event.xexpose.window == window->image.id)
  3396.           {
  3397.             XRefreshWindow(display,&window->image,&event);
  3398.             break;
  3399.           }
  3400.         if (event.xexpose.window == window->magnify.id)
  3401.           if (event.xexpose.count == 0)
  3402.             if (window->magnify.mapped)
  3403.               {
  3404.                 XMakeMagnifyImage(display,resource_info,window);
  3405.                 break;
  3406.               }
  3407.         if (event.xexpose.window != window->popup.id)
  3408.           break;
  3409.         if (event.xexpose.count != 0)
  3410.           break;
  3411.         state|=RedrawWidgetState;
  3412.         break;
  3413.       }
  3414.       case KeyPress:
  3415.       {
  3416.         static char
  3417.           command[MaxTextLength];
  3418.  
  3419.         static int
  3420.           length;
  3421.  
  3422.         static KeySym
  3423.           key_symbol;
  3424.  
  3425.         if (event.xkey.window != window->popup.id)
  3426.           break;
  3427.         /*
  3428.           Respond to a user key press.
  3429.         */
  3430.         length=XLookupString((XKeyEvent *) &event.xkey,command,sizeof(command),
  3431.           &key_symbol,(XComposeStatus *) NULL);
  3432.         *(command+length)='\0';
  3433.         if (key_symbol == XK_Up)
  3434.           if (MatteIsActive(scroll_info,event.xkey))
  3435.             if (slider_info.id > 0)
  3436.               {
  3437.                 /*
  3438.                   Move slider up.
  3439.                 */
  3440.                 slider_info.id--;
  3441.                 state|=RedrawListState;
  3442.                 break;
  3443.               }
  3444.         if (key_symbol == XK_Down)
  3445.           if (MatteIsActive(scroll_info,event.xkey))
  3446.             if (slider_info.id < files)
  3447.               {
  3448.                 /*
  3449.                   Move slider down.
  3450.                 */
  3451.                 slider_info.id++;
  3452.                 state|=RedrawListState;
  3453.                 break;
  3454.               }
  3455.         if (!MatteIsActive(reply_info,event.xkey))
  3456.           break;
  3457.         if ((key_symbol == XK_Return) || (key_symbol == XK_KP_Enter))
  3458.           {
  3459.             /*
  3460.               Read new directory or glob patterm.
  3461.             */
  3462.             if (*reply_info.text == '\0')
  3463.               break;
  3464.             if ((strchr(reply_info.text,'*') != (char *) NULL) ||
  3465.                 (strchr(reply_info.text,'?') != (char *) NULL) ||
  3466.                 (strchr(reply_info.text,'{') != (char *) NULL) ||
  3467.                 (strchr(reply_info.text,'}') != (char *) NULL) ||
  3468.                 (strchr(reply_info.text,'[') != (char *) NULL) ||
  3469.                 (strchr(reply_info.text,']') != (char *) NULL))
  3470.               (void) strcpy(glob_pattern,reply_info.text);
  3471.             else
  3472.               (void) strcpy(working_directory,reply_info.text);
  3473.             state|=UpdateListState;
  3474.             break;
  3475.           }
  3476.         if (key_symbol == XK_Control_L)
  3477.           {
  3478.             state|=ControlState;
  3479.             break;
  3480.           }
  3481.         if (state & ControlState)
  3482.           switch (key_symbol)
  3483.           {
  3484.             case XK_u:
  3485.             case XK_U:
  3486.             {
  3487.               key_symbol=XK_Delete;
  3488.               break;
  3489.             }
  3490.             default:
  3491.               break;
  3492.           }
  3493.         XEditText(display,&reply_info,key_symbol,command,state);
  3494.         XDrawMatteText(display,&window->popup,&reply_info);
  3495.         break;
  3496.       }
  3497.       case KeyRelease:
  3498.       {
  3499.         static char
  3500.           command[MaxTextLength];
  3501.  
  3502.         static KeySym
  3503.           key_symbol;
  3504.  
  3505.         if (event.xkey.window != window->popup.id)
  3506.           break;
  3507.         /*
  3508.           Respond to a user key release.
  3509.         */
  3510.         (void) XLookupString((XKeyEvent *) &event.xkey,command,sizeof(command),
  3511.           &key_symbol,(XComposeStatus *) NULL);
  3512.         if (key_symbol == XK_Control_L)
  3513.           state&=(~ControlState);
  3514.         break;
  3515.       }
  3516.       case MotionNotify:
  3517.       {
  3518.         /*
  3519.           Discard pending button motion events.
  3520.         */
  3521.         while (XCheckMaskEvent(display,ButtonMotionMask,&event));
  3522.         if (event.xmotion.window == window->image.id)
  3523.           {
  3524.             XTranslateCoordinates(display,event.xmotion.window,window->popup.id,
  3525.               0,0,&x_offset,&y_offset,&child);
  3526.             event.xmotion.x+=x_offset;
  3527.             event.xmotion.y+=y_offset;
  3528.           }
  3529.         if (slider_info.active)
  3530.           {
  3531.             /*
  3532.               Move slider matte.
  3533.             */
  3534.             slider_info.y=event.xmotion.y-
  3535.               ((slider_info.height+slider_info.bevel_width) >> 1)+1;
  3536.             if (slider_info.y < slider_info.min_y)
  3537.               slider_info.y=slider_info.min_y;
  3538.             if (slider_info.y > slider_info.max_y)
  3539.               slider_info.y=slider_info.max_y;
  3540.             slider_info.id=(files*(slider_info.y-slider_info.min_y+1))/
  3541.               (slider_info.max_y-slider_info.min_y+1);
  3542.             state|=RedrawListState;
  3543.             break;
  3544.           }
  3545.         if (up_info.raised == MatteIsActive(up_info,event.xmotion))
  3546.           {
  3547.             /*
  3548.               Up button status changed.
  3549.             */
  3550.             up_info.raised=!up_info.raised;
  3551.             XDrawBeveledButton(display,&window->popup,&up_info);
  3552.             break;
  3553.           }
  3554.         if (home_info.raised == MatteIsActive(home_info,event.xmotion))
  3555.           {
  3556.             /*
  3557.               Home button status changed.
  3558.             */
  3559.             home_info.raised=!home_info.raised;
  3560.             XDrawBeveledButton(display,&window->popup,&home_info);
  3561.             break;
  3562.           }
  3563.         if (action_info.raised == MatteIsActive(action_info,event.xmotion))
  3564.           {
  3565.             /*
  3566.               Action button status changed.
  3567.             */
  3568.             action_info.raised=!action_info.raised;
  3569.             XDrawBeveledButton(display,&window->popup,&action_info);
  3570.             break;
  3571.           }
  3572.         if (cancel_info.raised == MatteIsActive(cancel_info,event.xmotion))
  3573.           {
  3574.             /*
  3575.               Cancel button status changed.
  3576.             */
  3577.             cancel_info.raised=!cancel_info.raised;
  3578.             XDrawBeveledButton(display,&window->popup,&cancel_info);
  3579.             break;
  3580.           }
  3581.         break;
  3582.       }
  3583.       case SelectionClear:
  3584.       {
  3585.         reply_info.highlight=False;
  3586.         XDrawMatteText(display,&window->popup,&reply_info);
  3587.         break;
  3588.       }
  3589.       case SelectionNotify:
  3590.       {
  3591.         Atom
  3592.           type;
  3593.  
  3594.         int
  3595.           format,
  3596.           status;
  3597.  
  3598.         unsigned char
  3599.           *data;
  3600.  
  3601.         unsigned long
  3602.           after,
  3603.           length;
  3604.  
  3605.         /*
  3606.           Obtain response from primary selection.
  3607.         */
  3608.         if (event.xselection.property == (Atom) None)
  3609.           break;
  3610.         status=XGetWindowProperty(display,event.xselection.requestor,
  3611.           event.xselection.property,0L,2047L,True,XA_STRING,&type,&format,
  3612.           &length,&after,&data);
  3613.         if ((status != Success) || (type != XA_STRING) || (format == 32) ||
  3614.             (length == 0))
  3615.           break;
  3616.         if ((strlen(reply_info.text)+length) >= MaxTextLength)
  3617.           XBell(display,0);
  3618.         else
  3619.           {
  3620.             /*
  3621.               Insert primary selection in reply text.
  3622.             */
  3623.             *(data+length)='\0';
  3624.             XEditText(display,&reply_info,(KeySym) XK_Insert,(char *) data,
  3625.               state);
  3626.             XDrawMatteText(display,&window->popup,&reply_info);
  3627.           }
  3628.         XFree((void *) data);
  3629.         break;
  3630.       }
  3631.       case SelectionRequest:
  3632.       {
  3633.         XSelectionEvent
  3634.           notify;
  3635.  
  3636.         XSelectionRequestEvent
  3637.           *request;
  3638.  
  3639.         if (!reply_info.highlight)
  3640.           break;
  3641.         /*
  3642.           Set primary selection.
  3643.         */
  3644.         request=(&(event.xselectionrequest));
  3645.         XChangeProperty(request->display,request->requestor,request->property,
  3646.           request->target,8,PropModeReplace,primary_selection,
  3647.           strlen(primary_selection));
  3648.         notify.type=SelectionNotify;
  3649.         notify.display=request->display;
  3650.         notify.requestor=request->requestor;
  3651.         notify.selection=request->selection;
  3652.         notify.target=request->target;
  3653.         notify.time=request->time;
  3654.         if (request->property == None)
  3655.           notify.property=request->target;
  3656.         else
  3657.           notify.property=request->property;
  3658.         (void) XSendEvent(request->display,request->requestor,False,0,
  3659.           (XEvent *) ¬ify);
  3660.       }
  3661.       default:
  3662.         break;
  3663.     }
  3664.     if (state & UpdateConfigurationState)
  3665.       {
  3666.         /*
  3667.           Initialize button information.
  3668.         */
  3669.         XGetWidgetInfo(CancelButtonText,&cancel_info);
  3670.         cancel_info.width=width;
  3671.         cancel_info.height=(3*height) >> 1;
  3672.         cancel_info.x=window->popup.width-cancel_info.width-
  3673.           font_info->max_bounds.width-2;
  3674.         cancel_info.y=window->popup.height-cancel_info.height-
  3675.           font_info->max_bounds.width;
  3676.         XGetWidgetInfo(action,&action_info);
  3677.         action_info.width=width;
  3678.         action_info.height=(3*height) >> 1;
  3679.         action_info.x=cancel_info.x-(cancel_info.width+
  3680.           (font_info->max_bounds.width >> 1)+(action_info.bevel_width << 1));
  3681.         action_info.y=cancel_info.y;
  3682.         XGetWidgetInfo(UpButtonText,&up_info);
  3683.         up_info.width=width;
  3684.         up_info.height=(3*height) >> 1;
  3685.         up_info.x=font_info->max_bounds.width;
  3686.         up_info.y=((5*font_info->max_bounds.width) >> 1)+height;
  3687.         XGetWidgetInfo(HomeButtonText,&home_info);
  3688.         home_info.width=width;
  3689.         home_info.height=(3*height) >> 1;
  3690.         home_info.x=font_info->max_bounds.width;
  3691.         home_info.y=up_info.y+up_info.height+font_info->max_bounds.width;
  3692.         /*
  3693.           Initialize reply information.
  3694.         */
  3695.         XGetWidgetInfo(reply,&reply_info);
  3696.         reply_info.raised=False;
  3697.         reply_info.bevel_width--;
  3698.         reply_info.width=window->popup.width-width-
  3699.           ((6*font_info->max_bounds.width) >> 1);
  3700.         reply_info.height=height << 1;
  3701.         reply_info.x=width+(font_info->max_bounds.width << 1);
  3702.         reply_info.y=
  3703.           action_info.y-reply_info.height-font_info->max_bounds.width;
  3704.         /*
  3705.           Initialize scroll information.
  3706.         */
  3707.         XGetWidgetInfo((char *) NULL,&scroll_info);
  3708.         scroll_info.bevel_width--;
  3709.         scroll_info.width=height;
  3710.         scroll_info.height=
  3711.           reply_info.y-up_info.y-(font_info->max_bounds.width >> 1);
  3712.         scroll_info.x=reply_info.x+(reply_info.width-scroll_info.width);
  3713.         scroll_info.y=up_info.y-reply_info.bevel_width;
  3714.         scroll_info.raised=False;
  3715.         scroll_info.trough=True;
  3716.         north_info=scroll_info;
  3717.         north_info.raised=True;
  3718.         north_info.width-=(north_info.bevel_width << 1);
  3719.         north_info.height=north_info.width-1;
  3720.         north_info.x+=north_info.bevel_width;
  3721.         north_info.y+=north_info.bevel_width;
  3722.         south_info=north_info;
  3723.         south_info.y=scroll_info.y+scroll_info.height-scroll_info.bevel_width-
  3724.           south_info.height;
  3725.         slider_info=north_info;
  3726.         slider_info.id=0;
  3727.         slider_info.width-=2;
  3728.         slider_info.min_y=north_info.y+north_info.height+north_info.bevel_width+
  3729.           slider_info.bevel_width+2;
  3730.         slider_info.height=
  3731.           scroll_info.height-((slider_info.min_y-scroll_info.y+1) << 1)+2;
  3732.         visible_filenames=
  3733.           (scroll_info.height-(height >> 3)-4)/((9*height) >> 3);
  3734.         if (files > visible_filenames)
  3735.           slider_info.height=(visible_filenames*slider_info.height)/files;
  3736.         slider_info.max_y=south_info.y-south_info.bevel_width-
  3737.           slider_info.height-slider_info.bevel_width;
  3738.         slider_info.x=scroll_info.x+slider_info.bevel_width+1;
  3739.         slider_info.y=slider_info.min_y;
  3740.         expose_info=scroll_info;
  3741.         expose_info.y=slider_info.y;
  3742.         /*
  3743.           Initialize list information.
  3744.         */
  3745.         XGetWidgetInfo((char *) NULL,&list_info);
  3746.         list_info.raised=False;
  3747.         list_info.bevel_width--;
  3748.         list_info.width=
  3749.           scroll_info.x-reply_info.x-(font_info->max_bounds.width >> 1);
  3750.         list_info.height=scroll_info.height;
  3751.         list_info.x=reply_info.x;
  3752.         list_info.y=scroll_info.y;
  3753.         /*
  3754.           Initialize text information.
  3755.         */
  3756.         XGetWidgetInfo(text,&text_info);
  3757.         text_info.width=reply_info.width;
  3758.         text_info.height=height;
  3759.         text_info.x=list_info.x-(font_info->max_bounds.width >> 1);
  3760.         text_info.y=font_info->max_bounds.width;
  3761.         /*
  3762.           Initialize selection information.
  3763.         */
  3764.         XGetWidgetInfo((char *) NULL,&selection_info);
  3765.         selection_info.width=list_info.width;
  3766.         selection_info.height=(9*height) >> 3;
  3767.         selection_info.x=list_info.x;
  3768.         state&=(~UpdateConfigurationState);
  3769.       }
  3770.     if (state & RedrawWidgetState)
  3771.       {
  3772.         /*
  3773.           Redraw file browser window.
  3774.         */
  3775.         XClearWindow(display,window->popup.id);
  3776.         x=font_info->max_bounds.width;
  3777.         y=text_info.y+((text_info.height-height) >> 1)+font_info->ascent;
  3778.         XDrawString(display,window->popup.id,window->popup.annotate_context,
  3779.           x,y,DirectoryText,strlen(DirectoryText));
  3780.         (void) sprintf(text_info.text,"%s/%s",working_directory,glob_pattern);
  3781.         XDrawWidgetText(display,&window->popup,&text_info);
  3782.         XDrawBeveledButton(display,&window->popup,&up_info);
  3783.         XDrawBeveledButton(display,&window->popup,&home_info);
  3784.         XDrawBeveledMatte(display,&window->popup,&list_info);
  3785.         XDrawBeveledMatte(display,&window->popup,&scroll_info);
  3786.         XDrawTriangleNorth(display,&window->popup,&north_info);
  3787.         XDrawBeveledButton(display,&window->popup,&slider_info);
  3788.         XDrawTriangleSouth(display,&window->popup,&south_info);
  3789.         x=font_info->max_bounds.width;
  3790.         y=reply_info.y+((reply_info.height-height) >> 1)+font_info->ascent;
  3791.         XDrawString(display,window->popup.id,window->popup.annotate_context,
  3792.           x,y,FilenameText,strlen(FilenameText));
  3793.         XDrawBeveledMatte(display,&window->popup,&reply_info);
  3794.         XDrawMatteText(display,&window->popup,&reply_info);
  3795.         XDrawBeveledButton(display,&window->popup,&action_info);
  3796.         XDrawBeveledButton(display,&window->popup,&cancel_info);
  3797.         XHighlightWidget(display,&window->popup,4,4);
  3798.         selection_info.id=(~0);
  3799.         state|=RedrawListState;
  3800.         state&=(~RedrawWidgetState);
  3801.       }
  3802.     if (state & UpdateListState)
  3803.       {
  3804.         char
  3805.           **checklist;
  3806.  
  3807.         int
  3808.           number_files;
  3809.  
  3810.         /*
  3811.           Update file list.
  3812.         */
  3813.         checklist=ListFiles(working_directory,glob_pattern,&number_files);
  3814.         if (checklist == (char **) NULL)
  3815.           {
  3816.             /*
  3817.               Reply is a filename, exit.
  3818.             */
  3819.             action_info.raised=False;
  3820.             XDrawBeveledButton(display,&window->popup,&action_info);
  3821.             break;
  3822.           }
  3823.         for (i=0; i < files; i++)
  3824.           (void) free((char *) filelist[i]);
  3825.         if (filelist != (char **) NULL)
  3826.           (void) free((char *) filelist);
  3827.         filelist=checklist;
  3828.         files=number_files;
  3829.         /*
  3830.           Update file list.
  3831.         */
  3832.         if (filelist == (char **) NULL)
  3833.           {
  3834.             /*
  3835.               Reply is a filename, exit.
  3836.             */
  3837.             action_info.raised=False;
  3838.             XDrawBeveledButton(display,&window->popup,&action_info);
  3839.             break;
  3840.           }
  3841.         slider_info.height=
  3842.           scroll_info.height-((slider_info.min_y-scroll_info.y+1) << 1)+1;
  3843.         if (files > visible_filenames)
  3844.           slider_info.height=(visible_filenames*slider_info.height)/files;
  3845.         slider_info.max_y=south_info.y-south_info.bevel_width-
  3846.           slider_info.height-slider_info.bevel_width-1;
  3847.         slider_info.id=0;
  3848.         slider_info.y=slider_info.min_y;
  3849.         expose_info.y=slider_info.y;
  3850.         selection_info.id=(~0);
  3851.         list_info.id=(~0);
  3852.         state|=RedrawListState;
  3853.         /*
  3854.           Redraw directory name & reply.
  3855.         */
  3856.         *reply_info.text='\0';
  3857.         reply_info.cursor=reply_info.text;
  3858.         (void) sprintf(text_info.text,"%s/%s",working_directory,glob_pattern);
  3859.         XDrawWidgetText(display,&window->popup,&text_info);
  3860.         XDrawMatteText(display,&window->popup,&reply_info);
  3861.         XDrawBeveledMatte(display,&window->popup,&scroll_info);
  3862.         XDrawTriangleNorth(display,&window->popup,&north_info);
  3863.         XDrawBeveledButton(display,&window->popup,&slider_info);
  3864.         XDrawTriangleSouth(display,&window->popup,&south_info);
  3865.         XHighlightWidget(display,&window->popup,4,4);
  3866.         state&=(~UpdateListState);
  3867.       }
  3868.     if (state & RedrawListState)
  3869.       {
  3870.         /*
  3871.           Determine slider id and position.
  3872.         */
  3873.         if (slider_info.id >= files)
  3874.           slider_info.id=files-1;
  3875.         if ((slider_info.id < 0) || (files <= visible_filenames))
  3876.           slider_info.id=0;
  3877.         slider_info.y=slider_info.min_y;
  3878.         if (files > 0)
  3879.           slider_info.y+=
  3880.             slider_info.id*(slider_info.max_y-slider_info.min_y+1)/files;
  3881.         if (slider_info.id != selection_info.id)
  3882.           {
  3883.             /*
  3884.               Redraw scroll bar and file names.
  3885.             */
  3886.             selection_info.id=slider_info.id;
  3887.             selection_info.y=list_info.y+(height >> 3)+2;
  3888.             for (i=0; i < visible_filenames; i++)
  3889.             {
  3890.               selection_info.raised=(slider_info.id+i) != list_info.id;
  3891.               selection_info.text=(char *) NULL;
  3892.               if ((slider_info.id+i) < files)
  3893.                 selection_info.text=filelist[slider_info.id+i];
  3894.               XDrawWidgetText(display,&window->popup,&selection_info);
  3895.               selection_info.y+=(int) selection_info.height;
  3896.             }
  3897.             /*
  3898.               Update slider.
  3899.             */
  3900.             if (slider_info.y > expose_info.y)
  3901.               {
  3902.                 expose_info.height=slider_info.y-expose_info.y;
  3903.                 expose_info.y=slider_info.y-expose_info.height-
  3904.                   slider_info.bevel_width-1;
  3905.               }
  3906.             else
  3907.               {
  3908.                 expose_info.height=expose_info.y-slider_info.y;
  3909.                 expose_info.y=slider_info.y+slider_info.height+
  3910.                   slider_info.bevel_width+1;
  3911.               }
  3912.             XDrawTriangleNorth(display,&window->popup,&north_info);
  3913.             XDrawMatte(display,&window->popup,&expose_info);
  3914.             XDrawBeveledButton(display,&window->popup,&slider_info);
  3915.             XDrawTriangleSouth(display,&window->popup,&south_info);
  3916.             expose_info.y=slider_info.y;
  3917.           }
  3918.         state&=(~RedrawListState);
  3919.       }
  3920.   } while (!(state & ExitState));
  3921.   XDefineCursor(display,window->image.id,window->image.cursor);
  3922.   XWithdrawWindow(display,window->popup.id,window->popup.screen);
  3923.   XDelay(display,SuspendTime << 2);
  3924.   while (XCheckTypedWindowEvent(display,window->image.id,Expose,&event))
  3925.     XRefreshWindow(display,&window->image,&event);
  3926.   /*
  3927.     Free file list.
  3928.   */
  3929.   for (i=0; i < files; i++)
  3930.     (void) free((char *) filelist[i]);
  3931.   if (filelist != (char **) NULL)
  3932.     (void) free((char *) filelist);
  3933. }
  3934.  
  3935. /*
  3936. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  3937. %                                                                             %
  3938. %                                                                             %
  3939. %                                                                             %
  3940. %   X F o n t B r o w s e r W i d g e t                                       %
  3941. %                                                                             %
  3942. %                                                                             %
  3943. %                                                                             %
  3944. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  3945. %
  3946. %  Function XFontBrowserWidget displays a popup window with a font query to
  3947. %  the user.  The user keys a reply and presses the Action or Cancel button
  3948. %  to exit.  The typed text is returned as the reply function parameter.
  3949. %
  3950. %  The format of the XFontBrowserWidget routine is:
  3951. %
  3952. %    XFontBrowserWidget(display,resource_info,window,action,reply)
  3953. %
  3954. %  A description of each parameter follows:
  3955. %
  3956. %    o display: Specifies a connection to an X server;  returned from
  3957. %      XOpenDisplay.
  3958. %
  3959. %    o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
  3960. %
  3961. %    o window: Specifies a pointer to a XWindows structure.
  3962. %
  3963. %    o action: Specifies a pointer to the action of this widget.
  3964. %
  3965. %    o reply: The response from the user is returned in this parameter.
  3966. %
  3967. %
  3968. */
  3969. static int FontCompare(x,y)
  3970. const void
  3971.   *x,
  3972.   *y;
  3973. {
  3974.   register char
  3975.     *p,
  3976.     *q;
  3977.  
  3978.   p=(char *) *((char **) x);
  3979.   q=(char *) *((char **) y);
  3980.   while ((*p != '\0') && (*q != '\0') && (*p == *q))
  3981.   {
  3982.     p++;
  3983.     q++;
  3984.   }
  3985.   return(*p-(*q));
  3986. }
  3987.  
  3988. void XFontBrowserWidget(display,resource_info,window,action,reply)
  3989. Display
  3990.   *display;
  3991.  
  3992. XResourceInfo
  3993.   *resource_info;
  3994.  
  3995. XWindows
  3996.   *window;
  3997.  
  3998. char
  3999.   *action,
  4000.   *reply;
  4001. {
  4002. #define BackButtonText  "Back"
  4003. #define CancelButtonText  "Cancel"
  4004. #define FontnameText  "Name:"
  4005. #define FontPatternText  "Pattern:"
  4006. #define ResetButtonText  "Reset"
  4007.  
  4008.   char
  4009.     back_pattern[MaxTextLength],
  4010.     **fontlist,
  4011.     **listhead,
  4012.     primary_selection[MaxTextLength],
  4013.     reset_pattern[MaxTextLength],
  4014.     text[MaxTextLength];
  4015.  
  4016.   int
  4017.     fonts,
  4018.     x,
  4019.     x_offset,
  4020.     y,
  4021.     y_offset;
  4022.  
  4023.   register int
  4024.     i;
  4025.  
  4026.   static char
  4027.     glob_pattern[MaxTextLength] = "*";
  4028.  
  4029.   unsigned int
  4030.     delay,
  4031.     height,
  4032.     limit,
  4033.     mask,
  4034.     text_width,
  4035.     visible_fonts,
  4036.     width;
  4037.  
  4038.   unsigned long
  4039.     state;
  4040.  
  4041.   Window
  4042.     child,
  4043.     root_window;
  4044.  
  4045.   XEvent
  4046.     event;
  4047.  
  4048.   XFontStruct
  4049.     *font_info;
  4050.  
  4051.   XTextProperty
  4052.     window_name;
  4053.  
  4054.   XWidgetInfo
  4055.     action_info,
  4056.     back_info,
  4057.     cancel_info,
  4058.     expose_info,
  4059.     list_info,
  4060.     mode_info,
  4061.     north_info,
  4062.     reply_info,
  4063.     reset_info,
  4064.     scroll_info,
  4065.     selection_info,
  4066.     slider_info,
  4067.     south_info,
  4068.     text_info;
  4069.  
  4070.   XWindowChanges
  4071.     window_changes;
  4072.  
  4073.   /*
  4074.     Get font list and sort in ascending order.
  4075.   */
  4076.   XDefineCursor(display,window->image.id,window->image.busy_cursor);
  4077.   XFlush(display);
  4078.   (void) strcpy(back_pattern,glob_pattern);
  4079.   (void) strcpy(reset_pattern,"*");
  4080.   fontlist=XListFonts(display,glob_pattern,32767,&fonts);
  4081.   if (fonts == 0)
  4082.     {
  4083.       /*
  4084.         Pattern failed, obtain all the fonts.
  4085.       */
  4086.       XNoticeWidget(display,resource_info,window,"Unable to obtain fonts names",
  4087.         glob_pattern);
  4088.       (void) strcpy(glob_pattern,"*");
  4089.       fontlist=XListFonts(display,glob_pattern,32767,&fonts);
  4090.       if (fontlist == (char **) NULL)
  4091.         {
  4092.           XNoticeWidget(display,resource_info,window,
  4093.             "Unable to obtain fonts names",glob_pattern);
  4094.           return;
  4095.         }
  4096.     }
  4097.   /*
  4098.     Sort font list in ascending order.
  4099.   */
  4100.   listhead=fontlist;
  4101.   fontlist=(char **) malloc(fonts*sizeof(char **));
  4102.   if (fontlist == (char **) NULL)
  4103.     {
  4104.       XNoticeWidget(display,resource_info,window,"Unable to view fonts",
  4105.         "Memory allocation failed");
  4106.       return;
  4107.     }
  4108.   for (i=0; i < fonts; i++)
  4109.     fontlist[i]=listhead[i];
  4110.   (void) qsort((void *) fontlist,fonts,sizeof(char **),FontCompare);
  4111.   /*
  4112.     Determine popup window attributes.
  4113.   */
  4114.   font_info=window->popup.font_info;
  4115.   text_width=0;
  4116.   for (i=0; i < fonts; i++)
  4117.     if (XTextWidth(font_info,fontlist[i],strlen(fontlist[i])) > text_width)
  4118.       text_width=XTextWidth(font_info,fontlist[i],strlen(fontlist[i]));
  4119.   width=XTextWidth(font_info,action,strlen(action));
  4120.   if (XTextWidth(font_info,CancelButtonText,strlen(CancelButtonText)) > width)
  4121.     width=XTextWidth(font_info,CancelButtonText,strlen(CancelButtonText));
  4122.   if (XTextWidth(font_info,ResetButtonText,strlen(ResetButtonText)) > width)
  4123.     width=XTextWidth(font_info,ResetButtonText,strlen(ResetButtonText));
  4124.   if (XTextWidth(font_info,BackButtonText,strlen(BackButtonText)) > width)
  4125.     width=XTextWidth(font_info,BackButtonText,strlen(BackButtonText));
  4126.   width+=font_info->max_bounds.width;
  4127.   if (XTextWidth(font_info,FontPatternText,strlen(FontPatternText)) > width)
  4128.     width=XTextWidth(font_info,FontPatternText,strlen(FontPatternText));
  4129.   if (XTextWidth(font_info,FontnameText,strlen(FontnameText)) > width)
  4130.     width=XTextWidth(font_info,FontnameText,strlen(FontnameText));
  4131.   height=font_info->ascent+font_info->descent;
  4132.   window->popup.width=width+text_width+6*font_info->max_bounds.width;
  4133.   window->popup.height=
  4134.     ((85*height) >> 2)+((13*font_info->max_bounds.width) >> 1)+4;
  4135.   window->popup.min_width=width+25*XTextWidth(font_info,"#",1)+
  4136.     4*font_info->max_bounds.width;
  4137.   window->popup.min_height=
  4138.     ((27*height) >> 1)+((13*font_info->max_bounds.width) >> 1)+4;
  4139.   /*
  4140.     Position popup window.
  4141.   */
  4142.   XQueryPointer(display,XRootWindow(display,window->popup.screen),&root_window,
  4143.     &root_window,&x,&y,&window->popup.x,&window->popup.y,&mask);
  4144.   if (window->popup.width < window->popup.min_width)
  4145.     window->popup.width=window->popup.min_width;
  4146.   window->popup.x-=((3*window->popup.width) >> 2);
  4147.   limit=XDisplayWidth(display,window->popup.screen)-window->popup.width;
  4148.   if (window->popup.x < 0)
  4149.     window->popup.x=0;
  4150.   else
  4151.     if (window->popup.x > limit)
  4152.       window->popup.x=limit;
  4153.   if (window->popup.height < window->popup.min_height)
  4154.     window->popup.height=window->popup.min_height;
  4155.   window->popup.y-=(window->popup.height >> 1);
  4156.   limit=XDisplayHeight(display,window->popup.screen)-window->popup.height;
  4157.   if (window->popup.y < 0)
  4158.     window->popup.y=0;
  4159.   else
  4160.     if (window->popup.y > limit)
  4161.       window->popup.y=limit;
  4162.   /*
  4163.     Map popup window.
  4164.   */
  4165.   (void) sprintf(window->popup.name,"Browse and Select a Font");
  4166.   (void) XStringListToTextProperty(&window->popup.name,1,&window_name);
  4167.   XSetWMName(display,window->popup.id,&window_name);
  4168.   window_changes.width=window->popup.width;
  4169.   window_changes.height=window->popup.height;
  4170.   window_changes.x=window->popup.x;
  4171.   window_changes.y=window->popup.y;
  4172.   XReconfigureWMWindow(display,window->popup.id,window->popup.screen,CWWidth |
  4173.     CWHeight | CWX | CWY,&window_changes);
  4174.   XMapRaised(display,window->popup.id);
  4175.   /*
  4176.     Respond to X events.
  4177.   */
  4178.   XGetWidgetInfo((char *) NULL,&north_info);
  4179.   XGetWidgetInfo((char *) NULL,&south_info);
  4180.   visible_fonts=0;
  4181.   delay=SuspendTime << 2;
  4182.   state=UpdateConfigurationState;
  4183.   do
  4184.   {
  4185.     /*
  4186.       Wait for next event.
  4187.     */
  4188.     if (north_info.raised && south_info.raised)
  4189.       XIfEvent(display,&event,XWidgetEvent,(char *) window);
  4190.     else
  4191.       {
  4192.         /*
  4193.           Brief delay before advancing scroll bar.
  4194.         */
  4195.         XDelay(display,delay);
  4196.         XCheckMaskEvent(display,ButtonReleaseMask,&event);
  4197.         delay=SuspendTime;
  4198.       }
  4199.     switch (event.type)
  4200.     {
  4201.       case ButtonPress:
  4202.       {
  4203.         if (event.xbutton.window != window->popup.id)
  4204.           {
  4205.             XBell(display,0);
  4206.             break;
  4207.           }
  4208.         if (MatteIsActive(slider_info,event.xbutton))
  4209.           {
  4210.             /*
  4211.               Track slider.
  4212.             */
  4213.             slider_info.active=True;
  4214.             break;
  4215.           }
  4216.         if (MatteIsActive(north_info,event.xbutton))
  4217.           if (slider_info.id > 0)
  4218.             {
  4219.               /*
  4220.                 Move slider up.
  4221.               */
  4222.               north_info.raised=False;
  4223.               slider_info.id--;
  4224.               state|=RedrawListState;
  4225.               break;
  4226.             }
  4227.         if (MatteIsActive(south_info,event.xbutton))
  4228.           if (slider_info.id < fonts)
  4229.             {
  4230.               /*
  4231.                 Move slider down.
  4232.               */
  4233.               south_info.raised=False;
  4234.               slider_info.id++;
  4235.               state|=RedrawListState;
  4236.               break;
  4237.             }
  4238.         if (MatteIsActive(scroll_info,event.xbutton))
  4239.           {
  4240.             /*
  4241.               Move slider.
  4242.             */
  4243.             if (event.xbutton.y < slider_info.y)
  4244.               slider_info.id-=(visible_fonts-1);
  4245.             else
  4246.               slider_info.id+=(visible_fonts-1);
  4247.             state|=RedrawListState;
  4248.             break;
  4249.           }
  4250.         if (MatteIsActive(list_info,event.xbutton))
  4251.           {
  4252.             unsigned int
  4253.               id;
  4254.  
  4255.             /*
  4256.               User pressed list matte.
  4257.             */
  4258.             id=slider_info.id+(event.xbutton.y-(list_info.y+(height >> 1))+1)/
  4259.               selection_info.height;
  4260.             if (id >= fonts)
  4261.               break;
  4262.             (void) strcpy(reply_info.text,fontlist[id]);
  4263.             reply_info.highlight=False;
  4264.             reply_info.marker=reply_info.text;
  4265.             reply_info.cursor=reply_info.text+strlen(reply_info.text);
  4266.             XDrawMatteText(display,&window->popup,&reply_info);
  4267.             state|=RedrawActionState;
  4268.             if (id == list_info.id)
  4269.               {
  4270.                 (void) strcpy(glob_pattern,reply_info.text);
  4271.                 state|=UpdateListState;
  4272.               }
  4273.             selection_info.id=(~0);
  4274.             list_info.id=id;
  4275.             state|=RedrawListState;
  4276.             break;
  4277.           }
  4278.         if (MatteIsActive(back_info,event.xbutton))
  4279.           {
  4280.             /*
  4281.               User pressed Back button.
  4282.             */
  4283.             back_info.raised=False;
  4284.             XDrawBeveledButton(display,&window->popup,&back_info);
  4285.             break;
  4286.           }
  4287.         if (MatteIsActive(reset_info,event.xbutton))
  4288.           {
  4289.             /*
  4290.               User pressed Reset button.
  4291.             */
  4292.             reset_info.raised=False;
  4293.             XDrawBeveledButton(display,&window->popup,&reset_info);
  4294.             break;
  4295.           }
  4296.         if (MatteIsActive(action_info,event.xbutton))
  4297.           {
  4298.             /*
  4299.               User pressed action button.
  4300.             */
  4301.             action_info.raised=False;
  4302.             XDrawBeveledButton(display,&window->popup,&action_info);
  4303.             break;
  4304.           }
  4305.         if (MatteIsActive(cancel_info,event.xbutton))
  4306.           {
  4307.             /*
  4308.               User pressed Cancel button.
  4309.             */
  4310.             cancel_info.raised=False;
  4311.             XDrawBeveledButton(display,&window->popup,&cancel_info);
  4312.             break;
  4313.           }
  4314.         if ((event.xbutton.button == Button3) &&
  4315.             (event.xbutton.state & Mod1Mask))
  4316.           {
  4317.             /*
  4318.               Convert Alt-Matte3 to Button2.
  4319.             */
  4320.             event.xbutton.button=Button2;
  4321.             event.xbutton.state&=(~Mod1Mask);
  4322.           }
  4323.         if (!MatteIsActive(reply_info,event.xbutton))
  4324.           break;
  4325.         if (event.xbutton.button != Button2)
  4326.           {
  4327.             static Time
  4328.               click_time;
  4329.  
  4330.             /*
  4331.               Move text cursor to position of button press.
  4332.             */
  4333.             x=event.xbutton.x-reply_info.x-(font_info->max_bounds.width >> 2);
  4334.             for (i=1; i <= (int) strlen(reply_info.marker); i++)
  4335.               if (XTextWidth(font_info,reply_info.marker,i) > x)
  4336.                 break;
  4337.             reply_info.cursor=reply_info.marker+i-1;
  4338.             if (event.xbutton.time < (click_time+DoubleClick))
  4339.               {
  4340.                 /*
  4341.                   Become the XA_PRIMARY selection owner.
  4342.                 */
  4343.                 (void) strcpy(primary_selection,reply_info.text);
  4344.                 XSetSelectionOwner(display,XA_PRIMARY,window->popup.id,
  4345.                   event.xbutton.time);
  4346.                 reply_info.highlight=XGetSelectionOwner(display,XA_PRIMARY) ==
  4347.                   window->popup.id;
  4348.               }
  4349.             XDrawMatteText(display,&window->popup,&reply_info);
  4350.             click_time=event.xbutton.time;
  4351.             break;
  4352.           }
  4353.         /*
  4354.           Request primary selection.
  4355.         */
  4356.         XConvertSelection(display,XA_PRIMARY,XA_STRING,XA_STRING,
  4357.           window->popup.id,event.xbutton.time);
  4358.         break;
  4359.       }
  4360.       case ButtonRelease:
  4361.       {
  4362.         if (!north_info.raised)
  4363.           {
  4364.             /*
  4365.               User released up button.
  4366.             */
  4367.             delay=SuspendTime << 2;
  4368.             north_info.raised=True;
  4369.             XDrawTriangleNorth(display,&window->popup,&north_info);
  4370.           }
  4371.         if (!south_info.raised)
  4372.           {
  4373.             /*
  4374.               User released down button.
  4375.             */
  4376.             delay=SuspendTime << 2;
  4377.             south_info.raised=True;
  4378.             XDrawTriangleSouth(display,&window->popup,&south_info);
  4379.           }
  4380.         if (slider_info.active)
  4381.           {
  4382.             /*
  4383.               Stop tracking slider.
  4384.             */
  4385.             slider_info.active=False;
  4386.             break;
  4387.           }
  4388.         if (!back_info.raised)
  4389.           {
  4390.             if (event.xbutton.window == window->popup.id)
  4391.               if (MatteIsActive(back_info,event.xbutton))
  4392.                 {
  4393.                   (void) strcpy(glob_pattern,back_pattern);
  4394.                   state|=UpdateListState;
  4395.                 }
  4396.             back_info.raised=True;
  4397.             XDrawBeveledButton(display,&window->popup,&back_info);
  4398.           }
  4399.         if (!reset_info.raised)
  4400.           {
  4401.             if (event.xbutton.window == window->popup.id)
  4402.               if (MatteIsActive(reset_info,event.xbutton))
  4403.                 {
  4404.                   (void) strcpy(back_pattern,glob_pattern);
  4405.                   (void) strcpy(glob_pattern,reset_pattern);
  4406.                   state|=UpdateListState;
  4407.                 }
  4408.             reset_info.raised=True;
  4409.             XDrawBeveledButton(display,&window->popup,&reset_info);
  4410.           }
  4411.         if (!action_info.raised)
  4412.           {
  4413.             if (event.xbutton.window == window->popup.id)
  4414.               if (MatteIsActive(action_info,event.xbutton))
  4415.                 if (*reply_info.text == '\0')
  4416.                   XBell(display,0);
  4417.                 else
  4418.                   state|=ExitState;
  4419.             action_info.raised=True;
  4420.             XDrawBeveledButton(display,&window->popup,&action_info);
  4421.           }
  4422.         if (!cancel_info.raised)
  4423.           {
  4424.             if (event.xbutton.window == window->popup.id)
  4425.               if (MatteIsActive(cancel_info,event.xbutton))
  4426.                 {
  4427.                   *reply_info.text='\0';
  4428.                   state|=ExitState;
  4429.                 }
  4430.             cancel_info.raised=True;
  4431.             XDrawBeveledButton(display,&window->popup,&cancel_info);
  4432.           }
  4433.         break;
  4434.       }
  4435.       case ConfigureNotify:
  4436.       {
  4437.         /*
  4438.           Update widget configuration.
  4439.         */
  4440.         if (event.xconfigure.window != window->popup.id)
  4441.           break;
  4442.         if ((window->popup.width != event.xconfigure.width) ||
  4443.             (window->popup.height != event.xconfigure.height))
  4444.           state|=RedrawWidgetState;
  4445.         window->popup.width=Max(event.xconfigure.width,window->popup.min_width);
  4446.         window->popup.height=
  4447.           Max(event.xconfigure.height,window->popup.min_height);
  4448.         state|=UpdateConfigurationState;
  4449.         break;
  4450.       }
  4451.       case Expose:
  4452.       {
  4453.         if (event.xexpose.window == window->image.id)
  4454.           {
  4455.             XRefreshWindow(display,&window->image,&event);
  4456.             break;
  4457.           }
  4458.         if (event.xexpose.window == window->magnify.id)
  4459.           if (event.xexpose.count == 0)
  4460.             if (window->magnify.mapped)
  4461.               {
  4462.                 XMakeMagnifyImage(display,resource_info,window);
  4463.                 break;
  4464.               }
  4465.         if (event.xexpose.window != window->popup.id)
  4466.           break;
  4467.         if (event.xexpose.count != 0)
  4468.           break;
  4469.         state|=RedrawWidgetState;
  4470.         break;
  4471.       }
  4472.       case KeyPress:
  4473.       {
  4474.         static char
  4475.           command[MaxTextLength];
  4476.  
  4477.         static int
  4478.           length;
  4479.  
  4480.         static KeySym
  4481.           key_symbol;
  4482.  
  4483.         if (event.xkey.window != window->popup.id)
  4484.           break;
  4485.         /*
  4486.           Respond to a user key press.
  4487.         */
  4488.         length=XLookupString((XKeyEvent *) &event.xkey,command,sizeof(command),
  4489.           &key_symbol,(XComposeStatus *) NULL);
  4490.         *(command+length)='\0';
  4491.         if (key_symbol == XK_Up)
  4492.           if (MatteIsActive(scroll_info,event.xkey))
  4493.             if (slider_info.id < fonts)
  4494.               {
  4495.                 /*
  4496.                   Move slider down.
  4497.                 */
  4498.                 slider_info.id++;
  4499.                 state|=RedrawListState;
  4500.                 break;
  4501.               }
  4502.         if (key_symbol == XK_Down)
  4503.           if (MatteIsActive(scroll_info,event.xkey))
  4504.             if (slider_info.id > 0)
  4505.               {
  4506.                 /*
  4507.                   Move slider up.
  4508.                 */
  4509.                 slider_info.id--;
  4510.                 state|=RedrawListState;
  4511.                 break;
  4512.               }
  4513.         if (!MatteIsActive(reply_info,event.xkey))
  4514.           break;
  4515.         if ((key_symbol == XK_Return) || (key_symbol == XK_KP_Enter))
  4516.           {
  4517.             /*
  4518.               Read new font or glob patterm.
  4519.             */
  4520.             if (*reply_info.text == '\0')
  4521.               break;
  4522.             (void) strcpy(back_pattern,glob_pattern);
  4523.             (void) strcpy(glob_pattern,reply_info.text);
  4524.             state|=UpdateListState;
  4525.             break;
  4526.           }
  4527.         if (key_symbol == XK_Control_L)
  4528.           {
  4529.             state|=ControlState;
  4530.             break;
  4531.           }
  4532.         if (state & ControlState)
  4533.           switch (key_symbol)
  4534.           {
  4535.             case XK_u:
  4536.             case XK_U:
  4537.             {
  4538.               key_symbol=XK_Delete;
  4539.               break;
  4540.             }
  4541.             default:
  4542.               break;
  4543.           }
  4544.         XEditText(display,&reply_info,key_symbol,command,state);
  4545.         XDrawMatteText(display,&window->popup,&reply_info);
  4546.         break;
  4547.       }
  4548.       case KeyRelease:
  4549.       {
  4550.         static char
  4551.           command[MaxTextLength];
  4552.  
  4553.         static KeySym
  4554.           key_symbol;
  4555.  
  4556.         if (event.xkey.window != window->popup.id)
  4557.           break;
  4558.         /*
  4559.           Respond to a user key release.
  4560.         */
  4561.         (void) XLookupString((XKeyEvent *) &event.xkey,command,sizeof(command),
  4562.           &key_symbol,(XComposeStatus *) NULL);
  4563.         if (key_symbol == XK_Control_L)
  4564.           state&=(~ControlState);
  4565.         break;
  4566.       }
  4567.       case MotionNotify:
  4568.       {
  4569.         /*
  4570.           Discard pending button motion events.
  4571.         */
  4572.         while (XCheckMaskEvent(display,ButtonMotionMask,&event));
  4573.         if (event.xmotion.window == window->image.id)
  4574.           {
  4575.             XTranslateCoordinates(display,event.xmotion.window,window->popup.id,
  4576.               0,0,&x_offset,&y_offset,&child);
  4577.             event.xmotion.x+=x_offset;
  4578.             event.xmotion.y+=y_offset;
  4579.           }
  4580.         if (slider_info.active)
  4581.           {
  4582.             /*
  4583.               Move slider matte.
  4584.             */
  4585.             slider_info.y=event.xmotion.y-
  4586.               ((slider_info.height+slider_info.bevel_width) >> 1)+1;
  4587.             if (slider_info.y < slider_info.min_y)
  4588.               slider_info.y=slider_info.min_y;
  4589.             if (slider_info.y > slider_info.max_y)
  4590.               slider_info.y=slider_info.max_y;
  4591.             slider_info.id=(fonts*(slider_info.y-slider_info.min_y+1))/
  4592.               (slider_info.max_y-slider_info.min_y+1);
  4593.             state|=RedrawListState;
  4594.             break;
  4595.           }
  4596.         if (back_info.raised == MatteIsActive(back_info,event.xmotion))
  4597.           {
  4598.             /*
  4599.               Back button status changed.
  4600.             */
  4601.             back_info.raised=!back_info.raised;
  4602.             XDrawBeveledButton(display,&window->popup,&back_info);
  4603.             break;
  4604.           }
  4605.         if (reset_info.raised == MatteIsActive(reset_info,event.xmotion))
  4606.           {
  4607.             /*
  4608.               Reset button status changed.
  4609.             */
  4610.             reset_info.raised=!reset_info.raised;
  4611.             XDrawBeveledButton(display,&window->popup,&reset_info);
  4612.             break;
  4613.           }
  4614.         if (action_info.raised == MatteIsActive(action_info,event.xmotion))
  4615.           {
  4616.             /*
  4617.               Action button status changed.
  4618.             */
  4619.             action_info.raised=!action_info.raised;
  4620.             XDrawBeveledButton(display,&window->popup,&action_info);
  4621.             break;
  4622.           }
  4623.         if (cancel_info.raised == MatteIsActive(cancel_info,event.xmotion))
  4624.           {
  4625.             /*
  4626.               Cancel button status changed.
  4627.             */
  4628.             cancel_info.raised=!cancel_info.raised;
  4629.             XDrawBeveledButton(display,&window->popup,&cancel_info);
  4630.             break;
  4631.           }
  4632.         break;
  4633.       }
  4634.       case SelectionClear:
  4635.       {
  4636.         reply_info.highlight=False;
  4637.         XDrawMatteText(display,&window->popup,&reply_info);
  4638.         break;
  4639.       }
  4640.       case SelectionNotify:
  4641.       {
  4642.         Atom
  4643.           type;
  4644.  
  4645.         int
  4646.           format,
  4647.           status;
  4648.  
  4649.         unsigned char
  4650.           *data;
  4651.  
  4652.         unsigned long
  4653.           after,
  4654.           length;
  4655.  
  4656.         /*
  4657.           Obtain response from primary selection.
  4658.         */
  4659.         if (event.xselection.property == (Atom) None)
  4660.           break;
  4661.         status=XGetWindowProperty(display,event.xselection.requestor,
  4662.           event.xselection.property,0L,2047L,True,XA_STRING,&type,&format,
  4663.           &length,&after,&data);
  4664.         if ((status != Success) || (type != XA_STRING) || (format == 32) ||
  4665.             (length == 0))
  4666.           break;
  4667.         if ((strlen(reply_info.text)+length) >= MaxTextLength)
  4668.           XBell(display,0);
  4669.         else
  4670.           {
  4671.             /*
  4672.               Insert primary selection in reply text.
  4673.             */
  4674.             *(data+length)='\0';
  4675.             XEditText(display,&reply_info,(KeySym) XK_Insert,(char *) data,
  4676.               state);
  4677.             XDrawMatteText(display,&window->popup,&reply_info);
  4678.             state|=RedrawActionState;
  4679.           }
  4680.         XFree((void *) data);
  4681.         break;
  4682.       }
  4683.       case SelectionRequest:
  4684.       {
  4685.         XSelectionEvent
  4686.           notify;
  4687.  
  4688.         XSelectionRequestEvent
  4689.           *request;
  4690.  
  4691.         /*
  4692.           Set XA_PRIMARY selection.
  4693.         */
  4694.         request=(&(event.xselectionrequest));
  4695.         XChangeProperty(request->display,request->requestor,request->property,
  4696.           request->target,8,PropModeReplace,primary_selection,
  4697.           strlen(primary_selection));
  4698.         notify.type=SelectionNotify;
  4699.         notify.display=request->display;
  4700.         notify.requestor=request->requestor;
  4701.         notify.selection=request->selection;
  4702.         notify.target=request->target;
  4703.         notify.time=request->time;
  4704.         if (request->property == None)
  4705.           notify.property=request->target;
  4706.         else
  4707.           notify.property=request->property;
  4708.         (void) XSendEvent(request->display,request->requestor,False,0,
  4709.           (XEvent *) ¬ify);
  4710.       }
  4711.       default:
  4712.         break;
  4713.     }
  4714.     if (state & UpdateConfigurationState)
  4715.       {
  4716.         /*
  4717.           Initialize button information.
  4718.         */
  4719.         XGetWidgetInfo(CancelButtonText,&cancel_info);
  4720.         cancel_info.width=width;
  4721.         cancel_info.height=(3*height) >> 1;
  4722.         cancel_info.x=window->popup.width-cancel_info.width-
  4723.           font_info->max_bounds.width-2;
  4724.         cancel_info.y=window->popup.height-cancel_info.height-
  4725.           font_info->max_bounds.width;
  4726.         XGetWidgetInfo(action,&action_info);
  4727.         action_info.width=width;
  4728.         action_info.height=(3*height) >> 1;
  4729.         action_info.x=cancel_info.x-(cancel_info.width+
  4730.           (font_info->max_bounds.width >> 1)+(action_info.bevel_width << 1));
  4731.         action_info.y=cancel_info.y;
  4732.         XGetWidgetInfo(BackButtonText,&back_info);
  4733.         back_info.width=width;
  4734.         back_info.height=(3*height) >> 1;
  4735.         back_info.x=font_info->max_bounds.width;
  4736.         back_info.y=((5*font_info->max_bounds.width) >> 1)+height;
  4737.         XGetWidgetInfo(ResetButtonText,&reset_info);
  4738.         reset_info.width=width;
  4739.         reset_info.height=(3*height) >> 1;
  4740.         reset_info.x=font_info->max_bounds.width;
  4741.         reset_info.y=back_info.y+back_info.height+font_info->max_bounds.width;
  4742.         /*
  4743.           Initialize reply information.
  4744.         */
  4745.         XGetWidgetInfo(reply,&reply_info);
  4746.         reply_info.raised=False;
  4747.         reply_info.bevel_width--;
  4748.         reply_info.width=window->popup.width-width-
  4749.           ((6*font_info->max_bounds.width) >> 1);
  4750.         reply_info.height=height << 1;
  4751.         reply_info.x=width+(font_info->max_bounds.width << 1);
  4752.         reply_info.y=
  4753.           action_info.y-(action_info.height << 1)-font_info->max_bounds.width;
  4754.         /*
  4755.           Initialize mode information.
  4756.         */
  4757.         XGetWidgetInfo(reply,&mode_info);
  4758.         mode_info.bevel_width=0;
  4759.         mode_info.width=action_info.x-reply_info.x-font_info->max_bounds.width;
  4760.         mode_info.height=action_info.height << 1;
  4761.         mode_info.x=reply_info.x;
  4762.         mode_info.y=action_info.y-action_info.height+action_info.bevel_width;
  4763.         /*
  4764.           Initialize scroll information.
  4765.         */
  4766.         XGetWidgetInfo((char *) NULL,&scroll_info);
  4767.         scroll_info.bevel_width--;
  4768.         scroll_info.width=height;
  4769.         scroll_info.height=
  4770.           reply_info.y-back_info.y-(font_info->max_bounds.width >> 1);
  4771.         scroll_info.x=reply_info.x+(reply_info.width-scroll_info.width);
  4772.         scroll_info.y=back_info.y-reply_info.bevel_width;
  4773.         scroll_info.raised=False;
  4774.         scroll_info.trough=True;
  4775.         north_info=scroll_info;
  4776.         north_info.raised=True;
  4777.         north_info.width-=(north_info.bevel_width << 1);
  4778.         north_info.height=north_info.width-1;
  4779.         north_info.x+=north_info.bevel_width;
  4780.         north_info.y+=north_info.bevel_width;
  4781.         south_info=north_info;
  4782.         south_info.y=scroll_info.y+scroll_info.height-scroll_info.bevel_width-
  4783.           south_info.height;
  4784.         slider_info=north_info;
  4785.         slider_info.id=0;
  4786.         slider_info.width-=2;
  4787.         slider_info.min_y=north_info.y+north_info.height+north_info.bevel_width+
  4788.           slider_info.bevel_width+2;
  4789.         slider_info.height=
  4790.           scroll_info.height-((slider_info.min_y-scroll_info.y+1) << 1)+2;
  4791.         visible_fonts=
  4792.           (scroll_info.height-(height >> 3)-4)/((9*height) >> 3);
  4793.         if (fonts > visible_fonts)
  4794.           slider_info.height=(visible_fonts*slider_info.height)/fonts;
  4795.         slider_info.max_y=south_info.y-south_info.bevel_width-
  4796.           slider_info.height-slider_info.bevel_width;
  4797.         slider_info.x=scroll_info.x+slider_info.bevel_width+1;
  4798.         slider_info.y=slider_info.min_y;
  4799.         expose_info=scroll_info;
  4800.         expose_info.y=slider_info.y;
  4801.         /*
  4802.           Initialize list information.
  4803.         */
  4804.         XGetWidgetInfo((char *) NULL,&list_info);
  4805.         list_info.raised=False;
  4806.         list_info.bevel_width--;
  4807.         list_info.width=
  4808.           scroll_info.x-reply_info.x-(font_info->max_bounds.width >> 1);
  4809.         list_info.height=scroll_info.height;
  4810.         list_info.x=reply_info.x;
  4811.         list_info.y=scroll_info.y;
  4812.         /*
  4813.           Initialize text information.
  4814.         */
  4815.         XGetWidgetInfo(text,&text_info);
  4816.         text_info.width=reply_info.width;
  4817.         text_info.height=height;
  4818.         text_info.x=list_info.x-(font_info->max_bounds.width >> 1);
  4819.         text_info.y=font_info->max_bounds.width;
  4820.         /*
  4821.           Initialize selection information.
  4822.         */
  4823.         XGetWidgetInfo((char *) NULL,&selection_info);
  4824.         selection_info.width=list_info.width;
  4825.         selection_info.height=(9*height) >> 3;
  4826.         selection_info.x=list_info.x;
  4827.         state&=(~UpdateConfigurationState);
  4828.       }
  4829.     if (state & RedrawWidgetState)
  4830.       {
  4831.         /*
  4832.           Redraw file browser window.
  4833.         */
  4834.         XClearWindow(display,window->popup.id);
  4835.         x=font_info->max_bounds.width;
  4836.         y=text_info.y+((text_info.height-height) >> 1)+font_info->ascent;
  4837.         XDrawString(display,window->popup.id,window->popup.annotate_context,
  4838.           x,y,FontPatternText,strlen(FontPatternText));
  4839.         (void) sprintf(text_info.text,"%s",glob_pattern);
  4840.         XDrawWidgetText(display,&window->popup,&text_info);
  4841.         XDrawBeveledButton(display,&window->popup,&back_info);
  4842.         XDrawBeveledButton(display,&window->popup,&reset_info);
  4843.         XDrawBeveledMatte(display,&window->popup,&list_info);
  4844.         XDrawBeveledMatte(display,&window->popup,&scroll_info);
  4845.         XDrawTriangleNorth(display,&window->popup,&north_info);
  4846.         XDrawBeveledButton(display,&window->popup,&slider_info);
  4847.         XDrawTriangleSouth(display,&window->popup,&south_info);
  4848.         x=font_info->max_bounds.width;
  4849.         y=reply_info.y+((reply_info.height-height) >> 1)+font_info->ascent;
  4850.         XDrawString(display,window->popup.id,window->popup.annotate_context,
  4851.           x,y,FontnameText,strlen(FontnameText));
  4852.         XDrawBeveledMatte(display,&window->popup,&reply_info);
  4853.         XDrawMatteText(display,&window->popup,&reply_info);
  4854.         XDrawBeveledButton(display,&window->popup,&action_info);
  4855.         XDrawBeveledButton(display,&window->popup,&cancel_info);
  4856.         XHighlightWidget(display,&window->popup,4,4);
  4857.         selection_info.id=(~0);
  4858.         state|=RedrawActionState;
  4859.         state|=RedrawListState;
  4860.         state&=(~RedrawWidgetState);
  4861.       }
  4862.     if (state & UpdateListState)
  4863.       {
  4864.         char
  4865.           **checklist;
  4866.  
  4867.         int
  4868.           number_fonts;
  4869.  
  4870.         /*
  4871.           Update font list.
  4872.         */
  4873.         checklist=XListFonts(display,glob_pattern,32767,&number_fonts);
  4874.         if (checklist == (char **) NULL)
  4875.           {
  4876.             if ((strchr(glob_pattern,'*') == (char *) NULL) &&
  4877.                 (strchr(glob_pattern,'?') == (char *) NULL))
  4878.               {
  4879.                 /*
  4880.                   Might be a scaleable font-- exit.
  4881.                 */
  4882.                 (void) strcpy(reply,glob_pattern);
  4883.                 (void) strcpy(glob_pattern,back_pattern);
  4884.                 action_info.raised=False;
  4885.                 XDrawBeveledButton(display,&window->popup,&action_info);
  4886.                 break;
  4887.               }
  4888.             (void) strcpy(glob_pattern,back_pattern);
  4889.             XBell(display,0);
  4890.           }
  4891.         else
  4892.           if (number_fonts == 1)
  4893.             {
  4894.               /*
  4895.                 Reply is a single font name-- exit.
  4896.               */
  4897.               (void) strcpy(reply,checklist[0]);
  4898.               (void) strcpy(glob_pattern,back_pattern);
  4899.               XFreeFontNames(checklist);
  4900.               action_info.raised=False;
  4901.               XDrawBeveledButton(display,&window->popup,&action_info);
  4902.               break;
  4903.             }
  4904.           else
  4905.             {
  4906.               XFreeFontNames(listhead);
  4907.               (void) free((char *) fontlist);
  4908.               fontlist=checklist;
  4909.               fonts=number_fonts;
  4910.             }
  4911.         /*
  4912.           Sort font list in ascending order.
  4913.         */
  4914.         listhead=fontlist;
  4915.         fontlist=(char **) malloc(fonts*sizeof(char **));
  4916.         if (fontlist == (char **) NULL)
  4917.           {
  4918.             XNoticeWidget(display,resource_info,window,"Unable to view fonts",
  4919.               "Memory allocation failed");
  4920.             return;
  4921.           }
  4922.         for (i=0; i < fonts; i++)
  4923.           fontlist[i]=listhead[i];
  4924.         (void) qsort((void *) fontlist,fonts,sizeof(char **),FontCompare);
  4925.         slider_info.height=
  4926.           scroll_info.height-((slider_info.min_y-scroll_info.y+1) << 1)+1;
  4927.         if (fonts > visible_fonts)
  4928.           slider_info.height=(visible_fonts*slider_info.height)/fonts;
  4929.         slider_info.max_y=south_info.y-south_info.bevel_width-
  4930.           slider_info.height-slider_info.bevel_width-1;
  4931.         slider_info.id=0;
  4932.         slider_info.y=slider_info.min_y;
  4933.         expose_info.y=slider_info.y;
  4934.         selection_info.id=(~0);
  4935.         list_info.id=(~0);
  4936.         state|=RedrawListState;
  4937.         /*
  4938.           Redraw font name & reply.
  4939.         */
  4940.         *reply_info.text='\0';
  4941.         reply_info.cursor=reply_info.text;
  4942.         (void) sprintf(text_info.text,"%s",glob_pattern);
  4943.         XDrawWidgetText(display,&window->popup,&text_info);
  4944.         XDrawMatteText(display,&window->popup,&reply_info);
  4945.         XDrawBeveledMatte(display,&window->popup,&scroll_info);
  4946.         XDrawTriangleNorth(display,&window->popup,&north_info);
  4947.         XDrawBeveledButton(display,&window->popup,&slider_info);
  4948.         XDrawTriangleSouth(display,&window->popup,&south_info);
  4949.         XHighlightWidget(display,&window->popup,4,4);
  4950.         state&=(~UpdateListState);
  4951.       }
  4952.     if (state & RedrawListState)
  4953.       {
  4954.         /*
  4955.           Determine slider id and position.
  4956.         */
  4957.         if (slider_info.id >= fonts)
  4958.           slider_info.id=fonts-1;
  4959.         if ((slider_info.id < 0) || (fonts <= visible_fonts))
  4960.           slider_info.id=0;
  4961.         slider_info.y=slider_info.min_y;
  4962.         if (fonts > 0)
  4963.           slider_info.y+=
  4964.             slider_info.id*(slider_info.max_y-slider_info.min_y+1)/fonts;
  4965.         if (slider_info.id != selection_info.id)
  4966.           {
  4967.             /*
  4968.               Redraw scroll bar and file names.
  4969.             */
  4970.             selection_info.id=slider_info.id;
  4971.             selection_info.y=list_info.y+(height >> 3)+2;
  4972.             for (i=0; i < visible_fonts; i++)
  4973.             {
  4974.               selection_info.raised=(slider_info.id+i) != list_info.id;
  4975.               selection_info.text=(char *) NULL;
  4976.               if ((slider_info.id+i) < fonts)
  4977.                 selection_info.text=fontlist[slider_info.id+i];
  4978.               XDrawWidgetText(display,&window->popup,&selection_info);
  4979.               selection_info.y+=(int) selection_info.height;
  4980.             }
  4981.             /*
  4982.               Update slider.
  4983.             */
  4984.             if (slider_info.y > expose_info.y)
  4985.               {
  4986.                 expose_info.height=slider_info.y-expose_info.y;
  4987.                 expose_info.y=slider_info.y-expose_info.height-
  4988.                   slider_info.bevel_width-1;
  4989.               }
  4990.             else
  4991.               {
  4992.                 expose_info.height=expose_info.y-slider_info.y;
  4993.                 expose_info.y=slider_info.y+slider_info.height+
  4994.                   slider_info.bevel_width+1;
  4995.               }
  4996.             XDrawTriangleNorth(display,&window->popup,&north_info);
  4997.             XDrawMatte(display,&window->popup,&expose_info);
  4998.             XDrawBeveledButton(display,&window->popup,&slider_info);
  4999.             XDrawTriangleSouth(display,&window->popup,&south_info);
  5000.             expose_info.y=slider_info.y;
  5001.           }
  5002.         state&=(~RedrawListState);
  5003.       }
  5004.     if (state & RedrawActionState)
  5005.       {
  5006.         XFontStruct
  5007.           *font_info,
  5008.           *save_info;
  5009.  
  5010.         /*
  5011.           Display the selected font in a drawing area.
  5012.         */
  5013.         save_info=window->popup.font_info;
  5014.         font_info=XLoadQueryFont(display,reply_info.text);
  5015.         if (font_info != (XFontStruct *) NULL)
  5016.           {
  5017.             window->popup.font_info=font_info;;
  5018.             XSetFont(display,window->popup.widget_context,font_info->fid);
  5019.           }
  5020.         XDrawBeveledButton(display,&window->popup,&mode_info);
  5021.         window->popup.font_info=save_info;
  5022.         if (font_info != (XFontStruct *) NULL)
  5023.           {
  5024.             XSetFont(display,window->popup.widget_context,
  5025.               window->popup.font_info->fid);
  5026.             XFreeFont(display,font_info);
  5027.           }
  5028.         XHighlightWidget(display,&window->popup,4,4);
  5029.         XDrawMatteText(display,&window->popup,&reply_info);
  5030.         state&=(~RedrawActionState);
  5031.       }
  5032.   } while (!(state & ExitState));
  5033.   XDefineCursor(display,window->image.id,window->image.cursor);
  5034.   XWithdrawWindow(display,window->popup.id,window->popup.screen);
  5035.   XDelay(display,SuspendTime << 2);
  5036.   while (XCheckTypedWindowEvent(display,window->image.id,Expose,&event))
  5037.     XRefreshWindow(display,&window->image,&event);
  5038.   /*
  5039.     Free font list.
  5040.   */
  5041.   XFreeFontNames(listhead);
  5042.   (void) free((char *) fontlist);
  5043. }
  5044.  
  5045. /*
  5046. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  5047. %                                                                             %
  5048. %                                                                             %
  5049. %                                                                             %
  5050. %   X M e n u W i d g e t                                                     %
  5051. %                                                                             %
  5052. %                                                                             %
  5053. %                                                                             %
  5054. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  5055. %
  5056. %  Function XMenuWidget maps a menu and returns the command pointed to by the
  5057. %  user when the button is released.
  5058. %
  5059. %  The format of the XMenuWidget routine is:
  5060. %
  5061. %    selection_number=XMenuWidget(display,window,x,y,menu_title,menu_selections,
  5062. %      number_selections,item)
  5063. %
  5064. %  A description of each parameter follows:
  5065. %
  5066. %    o selection_number: Specifies the number of the selection that the
  5067. %      user choose.
  5068. %
  5069. %    o display: Specifies a connection to an X server;  returned from
  5070. %      XOpenDisplay.
  5071. %
  5072. %    o window: Specifies a pointer to a XWindows structure.
  5073. %
  5074. %    o x: Specifies an unsigned integer representing the root offset in the
  5075. %      x-direction.
  5076. %
  5077. %    o y: Specifies an unsigned integer representing the root offset in the
  5078. %      y-direction.
  5079. %
  5080. %    o menu_title: Specifies a character string that describes the menu
  5081. %      selections.
  5082. %
  5083. %    o menu_selections: Specifies a pointer to one or more strings that
  5084. %      make up the choices in the menu.
  5085. %
  5086. %    o number_selections: Specifies the number of choices in the menu.
  5087. %
  5088. %    o item: Specifies a character array.  The item selected from the menu
  5089. %      is returned here.
  5090. %
  5091. %
  5092. */
  5093. int XMenuWidget(display,window,x,y,menu_title,menu_selections,number_selections,
  5094.   item)
  5095. Display
  5096.   *display;
  5097.  
  5098. XWindows
  5099.   *window;
  5100.  
  5101. int
  5102.   x,
  5103.   y;
  5104.  
  5105. char
  5106.   *menu_title,
  5107.   **menu_selections;
  5108.  
  5109. unsigned int
  5110.   number_selections;
  5111.  
  5112. char
  5113.   *item;
  5114. {
  5115.   Cursor
  5116.     cursor;
  5117.  
  5118.   int
  5119.     id;
  5120.  
  5121.   unsigned int
  5122.     height,
  5123.     limit,
  5124.     title_height,
  5125.     width;
  5126.  
  5127.   unsigned long
  5128.     state;
  5129.  
  5130.   XEvent
  5131.     event;
  5132.  
  5133.   XFontStruct
  5134.     *font_info;
  5135.  
  5136.   XSetWindowAttributes
  5137.     window_attributes;
  5138.  
  5139.   XWidgetInfo
  5140.     menu_info,
  5141.     selection_info;
  5142.  
  5143.   XWindowChanges
  5144.     window_changes;
  5145.  
  5146.   /*
  5147.     Determine popup window attributes.
  5148.   */
  5149.   font_info=window->popup.font_info;
  5150.   window->popup.width=XTextWidth(font_info,menu_title,strlen(menu_title));
  5151.   for (id=0; id < number_selections; id++)
  5152.   {
  5153.     width=XTextWidth(font_info,menu_selections[id],strlen(menu_selections[id]));
  5154.     if (width > window->popup.width)
  5155.       window->popup.width=width;
  5156.   }
  5157.   window->popup.width+=font_info->max_bounds.width+6;
  5158.   title_height=(font_info->descent+font_info->ascent) << 1;
  5159.   width=XTextWidth(font_info,menu_title,strlen(menu_title));
  5160.   height=(9*(font_info->ascent+font_info->descent)) >> 3;
  5161.   window->popup.height=title_height+number_selections*height+(height >> 2);
  5162.   window->popup.min_width=window->popup.width;
  5163.   window->popup.min_height=window->popup.height;
  5164.   /*
  5165.     Position popup window.
  5166.   */
  5167.   window->popup.x=x-(font_info->max_bounds.width >> 1);
  5168.   limit=XDisplayWidth(display,window->popup.screen)-window->popup.width;
  5169.   if (window->popup.x < 0)
  5170.     window->popup.x=0;
  5171.   else
  5172.     if (window->popup.x > limit)
  5173.       window->popup.x=limit;
  5174.   window->popup.y=y-((3*title_height) >> 2);
  5175.   limit=XDisplayHeight(display,window->popup.screen)-window->popup.height;
  5176.   if (window->popup.y < 0)
  5177.     window->popup.y=0;
  5178.   else
  5179.     if (window->popup.y > limit)
  5180.       window->popup.y=limit;
  5181.   /*
  5182.     Map popup window.
  5183.   */
  5184.   window_attributes.override_redirect=True;
  5185.   XChangeWindowAttributes(display,window->popup.id,CWOverrideRedirect,
  5186.     &window_attributes);
  5187.   window_changes.width=window->popup.width;
  5188.   window_changes.height=window->popup.height;
  5189.   window_changes.x=window->popup.x;
  5190.   window_changes.y=window->popup.y;
  5191.   XReconfigureWMWindow(display,window->popup.id,window->popup.screen,CWWidth |
  5192.     CWHeight | CWX | CWY,&window_changes);
  5193.   XMapRaised(display,window->popup.id);
  5194.   /*
  5195.     Respond to X events.
  5196.   */
  5197.   selection_info.height=height;
  5198.   cursor=XCreateFontCursor(display,XC_right_ptr);
  5199.   XDefineCursor(display,window->image.id,cursor);
  5200.   state=UpdateConfigurationState;
  5201.   do
  5202.   {
  5203.     /*
  5204.       Wait for next event.
  5205.     */
  5206.     XIfEvent(display,&event,XWidgetEvent,(char *) window);
  5207.     switch (event.type)
  5208.     {
  5209.       case ButtonPress:
  5210.         break;
  5211.       case ButtonRelease:
  5212.       {
  5213.         /*
  5214.           Exit menu.
  5215.         */
  5216.         *item='\0';
  5217.         state|=ExitState;
  5218.         break;
  5219.       }
  5220.       case ConfigureNotify:
  5221.       {
  5222.         /*
  5223.           Update widget configuration.
  5224.         */
  5225.         if (event.xconfigure.window != window->popup.id)
  5226.           break;
  5227.         if ((window->popup.width != event.xconfigure.width) ||
  5228.             (window->popup.height != event.xconfigure.height))
  5229.           state|=RedrawWidgetState;
  5230.         window->popup.width=Max(event.xconfigure.width,window->popup.min_width);
  5231.         window->popup.height=
  5232.           Max(event.xconfigure.height,window->popup.min_height);
  5233.         state|=UpdateConfigurationState;
  5234.         break;
  5235.       }
  5236.       case Expose:
  5237.       {
  5238.         if (event.xexpose.window != window->popup.id)
  5239.           break;
  5240.         if (event.xexpose.count != 0)
  5241.           break;
  5242.         state|=RedrawWidgetState;
  5243.         break;
  5244.       }
  5245.       case EnterNotify:
  5246.       {
  5247.         if (event.xcrossing.window != window->popup.id)
  5248.           break;
  5249.         id=((event.xcrossing.y-title_height)/(int) selection_info.height);
  5250.         if ((id < 0) || (id >= number_selections))
  5251.           break;
  5252.         /*
  5253.           Highlight this selection.
  5254.         */
  5255.         selection_info.id=id;
  5256.         selection_info.y=title_height+selection_info.id*selection_info.height;
  5257.         selection_info.raised=False;
  5258.         selection_info.text=menu_selections[selection_info.id];
  5259.         XDrawWidgetText(display,&window->popup,&selection_info);
  5260.         break;
  5261.       }
  5262.       case LeaveNotify:
  5263.       {
  5264.         if (event.xcrossing.window != window->popup.id)
  5265.           break;
  5266.         id=selection_info.id;
  5267.         if ((id < 0) || (id >= number_selections))
  5268.           break;
  5269.         /*
  5270.           Unhighlight last selection.
  5271.         */
  5272.         selection_info.id=(~0);
  5273.         selection_info.raised=True;
  5274.         selection_info.text=menu_selections[id];
  5275.         XDrawWidgetText(display,&window->popup,&selection_info);
  5276.         break;
  5277.       }
  5278.       case MotionNotify:
  5279.       {
  5280.         /*
  5281.           Discard pending button motion events.
  5282.         */
  5283.         if (event.xmotion.window != window->popup.id)
  5284.           break;
  5285.         while (XCheckMaskEvent(display,ButtonMotionMask,&event));
  5286.         /*
  5287.           Determine if pointer has moved to a new selection.
  5288.         */
  5289.         id=(event.xmotion.y-title_height)/(int) selection_info.height;
  5290.         if ((selection_info.id >= 0) && (selection_info.id < number_selections))
  5291.           {
  5292.             /*
  5293.               Unhighlight last selection.
  5294.             */
  5295.             if (id == selection_info.id)
  5296.               break;
  5297.             selection_info.raised=True;
  5298.             selection_info.text=menu_selections[selection_info.id];
  5299.             XDrawWidgetText(display,&window->popup,&selection_info);
  5300.           }
  5301.         selection_info.id=id;
  5302.         if ((id < 0) || (id >= number_selections))
  5303.           break;
  5304.         /*
  5305.           Highlight this selection.
  5306.         */
  5307.         selection_info.y=title_height+selection_info.id*selection_info.height;
  5308.         selection_info.raised=False;
  5309.         selection_info.text=menu_selections[selection_info.id];
  5310.         XDrawWidgetText(display,&window->popup,&selection_info);
  5311.         break;
  5312.       }
  5313.       default:
  5314.         break;
  5315.     }
  5316.     if (state & UpdateConfigurationState)
  5317.       {
  5318.         /*
  5319.           Initialize selection information.
  5320.         */
  5321.         XGetWidgetInfo((char *) NULL,&menu_info);
  5322.         menu_info.bevel_width--;
  5323.         menu_info.width=window->popup.width-((menu_info.bevel_width) << 1);
  5324.         menu_info.height=window->popup.height-((menu_info.bevel_width) << 1);
  5325.         menu_info.x=menu_info.bevel_width;
  5326.         menu_info.y=menu_info.bevel_width;
  5327.         XGetWidgetInfo((char *) NULL,&selection_info);
  5328.         selection_info.width=menu_info.width;
  5329.         selection_info.height=height;
  5330.         selection_info.x=menu_info.x;
  5331.         state&=(~UpdateConfigurationState);
  5332.       }
  5333.     if (state & RedrawWidgetState)
  5334.       {
  5335.         /*
  5336.           Redraw Menu widget.
  5337.         */
  5338.         XClearWindow(display,window->popup.id);
  5339.         XDrawBevel(display,&window->popup,&menu_info);
  5340.         y=title_height-1;
  5341.         XSetBevelColor(display,&window->popup,False);
  5342.         XDrawLine(display,window->popup.id,window->popup.widget_context,
  5343.           selection_info.x,y-1,(int) selection_info.width,y-1);
  5344.         XSetBevelColor(display,&window->popup,True);
  5345.         XDrawLine(display,window->popup.id,window->popup.widget_context,
  5346.           selection_info.x,y,(int) selection_info.width,y);
  5347.         XSetFillStyle(display,window->popup.widget_context,FillSolid);
  5348.         /*
  5349.           Draw menu selections.
  5350.         */
  5351.         selection_info.y=title_height >> 2;
  5352.         selection_info.text=menu_title;
  5353.         XDrawWidgetText(display,&window->popup,&selection_info);
  5354.         selection_info.y=title_height;
  5355.         for (id=0; id < number_selections; id++)
  5356.         {
  5357.           selection_info.text=menu_selections[id];
  5358.           XDrawWidgetText(display,&window->popup,&selection_info);
  5359.           selection_info.y+=(int) selection_info.height;
  5360.         }
  5361.         state&=(~RedrawWidgetState);
  5362.       }
  5363.     if (number_selections > 2)
  5364.       {
  5365.         /*
  5366.           Redraw Menu line.
  5367.         */
  5368.         y=title_height+selection_info.height*(number_selections-1);
  5369.         XSetBevelColor(display,&window->popup,False);
  5370.         XDrawLine(display,window->popup.id,window->popup.widget_context,
  5371.           selection_info.x,y-1,(int) selection_info.width,y-1);
  5372.         XSetBevelColor(display,&window->popup,True);
  5373.         XDrawLine(display,window->popup.id,window->popup.widget_context,
  5374.           selection_info.x,y,(int) selection_info.width,y);
  5375.         XSetFillStyle(display,window->popup.widget_context,FillSolid);
  5376.       }
  5377.   } while (!(state & ExitState));
  5378.   XDefineCursor(display,window->image.id,window->image.cursor);
  5379.   window_attributes.override_redirect=False;
  5380.   XChangeWindowAttributes(display,window->popup.id,CWOverrideRedirect,
  5381.     &window_attributes);
  5382.   XWithdrawWindow(display,window->popup.id,window->popup.screen);
  5383.   XFlush(display);
  5384.   if ((selection_info.id < 0) || (selection_info.id >= number_selections))
  5385.     return(~0);
  5386.   (void) strcpy(item,menu_selections[selection_info.id]);
  5387.   return(selection_info.id);
  5388. }
  5389.  
  5390. /*
  5391. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  5392. %                                                                             %
  5393. %                                                                             %
  5394. %                                                                             %
  5395. %   X N o t i c e W i d g e t                                                 %
  5396. %                                                                             %
  5397. %                                                                             %
  5398. %                                                                             %
  5399. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  5400. %
  5401. %  Function XNoticeWidget displays a popup window with a notice to the user.
  5402. %  The function returns when the user presses the "Dismiss" button.
  5403. %
  5404. %  The format of the XNoticeWidget routine is:
  5405. %
  5406. %    XNoticeWidget(display,resource_info,window,message,qualifier)
  5407. %
  5408. %  A description of each parameter follows:
  5409. %
  5410. %    o display: Specifies a connection to an X server;  returned from
  5411. %      XOpenDisplay.
  5412. %
  5413. %    o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
  5414. %
  5415. %    o window: Specifies a pointer to a XWindows structure.
  5416. %
  5417. %    o message: Specifies the message to display before terminating the
  5418. %      program.
  5419. %
  5420. %    o qualifier: Specifies any qualifier to the message.
  5421. %
  5422. %
  5423. */
  5424. void XNoticeWidget(display,resource_info,window,message,qualifier)
  5425. Display
  5426.   *display;
  5427.  
  5428. XResourceInfo
  5429.   *resource_info;
  5430.  
  5431. XWindows
  5432.   *window;
  5433.  
  5434. char
  5435.   *message,
  5436.   *qualifier;
  5437. {
  5438. #define DismissButtonText  "Dismiss"
  5439.  
  5440.   int
  5441.     limit,
  5442.     x,
  5443.     x_offset,
  5444.     y,
  5445.     y_offset;
  5446.  
  5447.   unsigned int
  5448.     height,
  5449.     mask,
  5450.     width;
  5451.  
  5452.   unsigned long
  5453.     state;
  5454.  
  5455.   Window
  5456.     child,
  5457.     root_window;
  5458.  
  5459.   XEvent
  5460.     event;
  5461.  
  5462.   XFontStruct
  5463.     *font_info;
  5464.  
  5465.   XTextProperty
  5466.     window_name;
  5467.  
  5468.   XWidgetInfo
  5469.     dismiss_info;
  5470.  
  5471.   XWindowChanges
  5472.     window_changes;
  5473.  
  5474.   /*
  5475.     Determine popup window attributes.
  5476.   */
  5477.   font_info=window->popup.font_info;
  5478.   width=XTextWidth(font_info,DismissButtonText,strlen(DismissButtonText));
  5479.   if (message != (char *) NULL)
  5480.     if (XTextWidth(font_info,message,strlen(message)) > width)
  5481.       width=XTextWidth(font_info,message,strlen(message));
  5482.   if (qualifier != (char *) NULL)
  5483.     if (XTextWidth(font_info,qualifier,strlen(qualifier)) > width)
  5484.       width=XTextWidth(font_info,qualifier,strlen(qualifier));
  5485.   height=(font_info->ascent+font_info->descent);
  5486.   window->popup.width=width+4*font_info->max_bounds.width;
  5487.   window->popup.height=12*height;
  5488.   window->popup.min_width=width+font_info->max_bounds.width;
  5489.   window->popup.min_height=7*height;
  5490.   /*
  5491.     Position popup window.
  5492.   */
  5493.   XQueryPointer(display,XRootWindow(display,window->popup.screen),&root_window,
  5494.     &root_window,&x,&y,&window->popup.x,&window->popup.y,&mask);
  5495.   if (window->popup.width < window->popup.min_width)
  5496.     window->popup.width=window->popup.min_width;
  5497.   window->popup.x-=(window->popup.width >> 1);
  5498.   limit=XDisplayWidth(display,window->popup.screen)-window->popup.width;
  5499.   if (window->popup.x < 0)
  5500.     window->popup.x=0;
  5501.   else
  5502.     if (window->popup.x > limit)
  5503.       window->popup.x=limit;
  5504.   if (window->popup.height < window->popup.min_height)
  5505.     window->popup.height=window->popup.min_height;
  5506.   window->popup.y-=(window->popup.height-3*height);
  5507.   limit=XDisplayHeight(display,window->popup.screen)-window->popup.height;
  5508.   if (window->popup.y < 0)
  5509.     window->popup.y=0;
  5510.   else
  5511.     if (window->popup.y > limit)
  5512.       window->popup.y=limit;
  5513.   /*
  5514.     Map popup window.
  5515.   */
  5516.   (void) sprintf(window->popup.name,"Notice");
  5517.   (void) XStringListToTextProperty(&window->popup.name,1,&window_name);
  5518.   XSetWMName(display,window->popup.id,&window_name);
  5519.   window_changes.width=window->popup.width;
  5520.   window_changes.height=window->popup.height;
  5521.   window_changes.x=window->popup.x;
  5522.   window_changes.y=window->popup.y;
  5523.   XReconfigureWMWindow(display,window->popup.id,window->popup.screen,CWWidth |
  5524.     CWHeight | CWX | CWY,&window_changes);
  5525.   XMapRaised(display,window->popup.id);
  5526.   XBell(display,0);
  5527.   /*
  5528.     Respond to X events.
  5529.   */
  5530.   state=UpdateConfigurationState;
  5531.   XDefineCursor(display,window->image.id,window->image.busy_cursor);
  5532.   do
  5533.   {
  5534.     /*
  5535.       Wait for next event.
  5536.     */
  5537.     XIfEvent(display,&event,XWidgetEvent,(char *) window);
  5538.     switch (event.type)
  5539.     {
  5540.       case ButtonPress:
  5541.       {
  5542.         if (event.xbutton.window != window->popup.id)
  5543.           {
  5544.             XBell(display,0);
  5545.             break;
  5546.           }
  5547.         if (MatteIsActive(dismiss_info,event.xbutton))
  5548.           {
  5549.             /*
  5550.               User pressed Dismiss button.
  5551.             */
  5552.             dismiss_info.raised=False;
  5553.             XDrawBeveledButton(display,&window->popup,&dismiss_info);
  5554.             break;
  5555.           }
  5556.         break;
  5557.       }
  5558.       case ButtonRelease:
  5559.       {
  5560.         if (!dismiss_info.raised)
  5561.           {
  5562.             if (event.xbutton.window == window->popup.id)
  5563.               if (MatteIsActive(dismiss_info,event.xbutton))
  5564.                 state|=ExitState;
  5565.             dismiss_info.raised=True;
  5566.             XDrawBeveledButton(display,&window->popup,&dismiss_info);
  5567.           }
  5568.         break;
  5569.       }
  5570.       case ConfigureNotify:
  5571.       {
  5572.         /*
  5573.           Update widget configuration.
  5574.         */
  5575.         if (event.xconfigure.window != window->popup.id)
  5576.           break;
  5577.         if ((window->popup.width != event.xconfigure.width) ||
  5578.             (window->popup.height != event.xconfigure.height))
  5579.           state|=RedrawWidgetState;
  5580.         window->popup.width=Max(event.xconfigure.width,window->popup.min_width);
  5581.         window->popup.height=
  5582.           Max(event.xconfigure.height,window->popup.min_height);
  5583.         state|=UpdateConfigurationState;
  5584.         break;
  5585.       }
  5586.       case Expose:
  5587.       {
  5588.         if (event.xexpose.window == window->image.id)
  5589.           {
  5590.             XRefreshWindow(display,&window->image,&event);
  5591.             break;
  5592.           }
  5593.         if (event.xexpose.window == window->magnify.id)
  5594.           if (event.xexpose.count == 0)
  5595.             if (window->magnify.mapped)
  5596.               {
  5597.                 XMakeMagnifyImage(display,resource_info,window);
  5598.                 break;
  5599.               }
  5600.         if (event.xexpose.window != window->popup.id)
  5601.           break;
  5602.         if (event.xexpose.count != 0)
  5603.           break;
  5604.         state|=RedrawWidgetState;
  5605.         break;
  5606.       }
  5607.       case KeyPress:
  5608.       {
  5609.         static char
  5610.           command[MaxTextLength];
  5611.  
  5612.         static KeySym
  5613.           key_symbol;
  5614.  
  5615.         if (event.xkey.window != window->popup.id)
  5616.           break;
  5617.         /*
  5618.           Respond to a user key press.
  5619.         */
  5620.         (void) XLookupString((XKeyEvent *) &event.xkey,command,sizeof(command),
  5621.           &key_symbol,(XComposeStatus *) NULL);
  5622.         if ((key_symbol == XK_Return) || (key_symbol == XK_KP_Enter))
  5623.           {
  5624.             dismiss_info.raised=False;
  5625.             XDrawBeveledButton(display,&window->popup,&dismiss_info);
  5626.             state|=ExitState;
  5627.             break;
  5628.           }
  5629.         break;
  5630.       }
  5631.       case MotionNotify:
  5632.       {
  5633.         /*
  5634.           Discard pending button motion events.
  5635.         */
  5636.         while (XCheckMaskEvent(display,ButtonMotionMask,&event));
  5637.         if (event.xmotion.window == window->image.id)
  5638.           {
  5639.             XTranslateCoordinates(display,event.xmotion.window,window->popup.id,
  5640.               0,0,&x_offset,&y_offset,&child);
  5641.             event.xmotion.x+=x_offset;
  5642.             event.xmotion.y+=y_offset;
  5643.           }
  5644.         if (dismiss_info.raised == MatteIsActive(dismiss_info,event.xmotion))
  5645.           {
  5646.             /*
  5647.               Dismiss button status changed.
  5648.             */
  5649.             dismiss_info.raised=!dismiss_info.raised;
  5650.             XDrawBeveledButton(display,&window->popup,&dismiss_info);
  5651.             break;
  5652.           }
  5653.         break;
  5654.       }
  5655.       default:
  5656.         break;
  5657.     }
  5658.     if (state & UpdateConfigurationState)
  5659.       {
  5660.         /*
  5661.           Initialize Dismiss button information.
  5662.         */
  5663.         XGetWidgetInfo(DismissButtonText,&dismiss_info);
  5664.         dismiss_info.width=font_info->max_bounds.width+
  5665.           XTextWidth(font_info,DismissButtonText,strlen(DismissButtonText));
  5666.         dismiss_info.height=(3*height) >> 1;
  5667.         dismiss_info.x=(window->popup.width >> 1)-(dismiss_info.width >> 1);
  5668.         dismiss_info.y=window->popup.height-(dismiss_info.height << 1);
  5669.         state&=(~UpdateConfigurationState);
  5670.       }
  5671.     if (state & RedrawWidgetState)
  5672.       {
  5673.         /*
  5674.           Redraw Notice widget.
  5675.         */
  5676.         XClearWindow(display,window->popup.id);
  5677.         width=XTextWidth(font_info,message,strlen(message));
  5678.         x=(window->popup.width >> 1)-(width >> 1);
  5679.         y=(window->popup.height >> 1)-(height << 1);
  5680.         XDrawString(display,window->popup.id,window->popup.annotate_context,x,y,
  5681.           message,strlen(message));
  5682.         if (qualifier != (char *) NULL)
  5683.           {
  5684.             width=XTextWidth(font_info,qualifier,strlen(qualifier));
  5685.             x=(window->popup.width >> 1)-(width >> 1);
  5686.             y+=height;
  5687.             XDrawString(display,window->popup.id,window->popup.annotate_context,
  5688.               x,y,qualifier,strlen(qualifier));
  5689.           }
  5690.         XDrawBeveledButton(display,&window->popup,&dismiss_info);
  5691.         XHighlightWidget(display,&window->popup,4,4);
  5692.         state&=(~RedrawWidgetState);
  5693.       }
  5694.   } while (!(state & ExitState));
  5695.   XDefineCursor(display,window->image.id,window->image.cursor);
  5696.   XWithdrawWindow(display,window->popup.id,window->popup.screen);
  5697.   XDelay(display,SuspendTime << 2);
  5698.   while (XCheckTypedWindowEvent(display,window->image.id,Expose,&event))
  5699.     XRefreshWindow(display,&window->image,&event);
  5700. }
  5701.  
  5702. /*
  5703. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  5704. %                                                                             %
  5705. %                                                                             %
  5706. %                                                                             %
  5707. %   X T e x t V i e w W i d g e t                                             %
  5708. %                                                                             %
  5709. %                                                                             %
  5710. %                                                                             %
  5711. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  5712. %
  5713. %  Function XTextViewWidget displays text in a popup window.
  5714. %
  5715. %  The format of the XTextViewWidget routine is:
  5716. %
  5717. %    XTextViewWidget(display,resource_info,window,title,textlist)
  5718. %
  5719. %  A description of each parameter follows:
  5720. %
  5721. %    o display: Specifies a connection to an X server;  returned from
  5722. %      XOpenDisplay.
  5723. %
  5724. %    o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
  5725. %
  5726. %    o window: Specifies a pointer to a XWindows structure.
  5727. %
  5728. %    o title: This character string is displayed at the top of the popup
  5729. %      window.
  5730. %
  5731. %    o textlist: This string list is displayed within the popup window.
  5732. %
  5733. %
  5734. */
  5735. void XTextViewWidget(display,resource_info,window,title,textlist)
  5736. Display
  5737.   *display;
  5738.  
  5739. XResourceInfo
  5740.   *resource_info;
  5741.  
  5742. XWindows
  5743.   *window;
  5744.  
  5745. char
  5746.   *title,
  5747.   **textlist;
  5748. {
  5749. #define DismissButtonText  "Dismiss"
  5750.  
  5751.   int
  5752.     x,
  5753.     x_offset,
  5754.     y,
  5755.     y_offset;
  5756.  
  5757.   register int
  5758.     i;
  5759.  
  5760.   unsigned int
  5761.     delay,
  5762.     height,
  5763.     limit,
  5764.     lines,
  5765.     mask,
  5766.     text_width,
  5767.     visible_lines,
  5768.     width;
  5769.  
  5770.   unsigned long
  5771.     state;
  5772.  
  5773.   Window
  5774.     child,
  5775.     root_window;
  5776.  
  5777.   XEvent
  5778.     event;
  5779.  
  5780.   XFontStruct
  5781.     *font_info;
  5782.  
  5783.   XTextProperty
  5784.     window_name;
  5785.  
  5786.   XWidgetInfo
  5787.     dismiss_info,
  5788.     expose_info,
  5789.     list_info,
  5790.     north_info,
  5791.     scroll_info,
  5792.     selection_info,
  5793.     slider_info,
  5794.     south_info;
  5795.  
  5796.   XWindowChanges
  5797.     window_changes;
  5798.  
  5799.   /*
  5800.     Convert text string to a text list.
  5801.   */
  5802.   XDefineCursor(display,window->image.id,window->image.busy_cursor);
  5803.   XFlush(display);
  5804.   if (textlist == (char **) NULL)
  5805.     {
  5806.       XNoticeWidget(display,resource_info,window,"No text to view",
  5807.         (char *) NULL);
  5808.       return;
  5809.     }
  5810.   /*
  5811.     Determine popup window attributes.
  5812.   */
  5813.   font_info=window->popup.font_info;
  5814.   text_width=0;
  5815.   for (i=0; textlist[i] != (char *) NULL; i++)
  5816.     if (XTextWidth(font_info,textlist[i],strlen(textlist[i])) > text_width)
  5817.       text_width=XTextWidth(font_info,textlist[i],strlen(textlist[i]));
  5818.   lines=i;
  5819.   width=XTextWidth(font_info,DismissButtonText,strlen(DismissButtonText));
  5820.   width+=font_info->max_bounds.width;
  5821.   height=font_info->ascent+font_info->descent;
  5822.   window->popup.width=text_width+5*font_info->max_bounds.width;
  5823.   window->popup.height=Min(Max(lines,3),24)*height+((13*height) >> 1)+
  5824.     ((9*font_info->max_bounds.width) >> 1);
  5825.   window->popup.min_width=25*XTextWidth(font_info,"#",1)+
  5826.     4*font_info->max_bounds.width;
  5827.   window->popup.min_height=3*height+((13*height) >> 1)+
  5828.     ((9*font_info->max_bounds.width) >> 1);
  5829.   /*
  5830.     Position popup window.
  5831.   */
  5832.   XQueryPointer(display,XRootWindow(display,window->popup.screen),&root_window,
  5833.     &root_window,&x,&y,&window->popup.x,&window->popup.y,&mask);
  5834.   if (window->popup.width < window->popup.min_width)
  5835.     window->popup.width=window->popup.min_width;
  5836.   window->popup.x-=((3*window->popup.width) >> 2);
  5837.   limit=XDisplayWidth(display,window->popup.screen)-window->popup.width;
  5838.   if (window->popup.x < 0)
  5839.     window->popup.x=0;
  5840.   else
  5841.     if (window->popup.x > limit)
  5842.       window->popup.x=limit;
  5843.   if (window->popup.height < window->popup.min_height)
  5844.     window->popup.height=window->popup.min_height;
  5845.   window->popup.y-=(window->popup.height >> 1);
  5846.   limit=XDisplayHeight(display,window->popup.screen)-window->popup.height;
  5847.   if (window->popup.y < 0)
  5848.     window->popup.y=0;
  5849.   else
  5850.     if (window->popup.y > limit)
  5851.       window->popup.y=limit;
  5852.   /*
  5853.     Map popup window.
  5854.   */
  5855.   (void) sprintf(window->popup.name,title);
  5856.   (void) XStringListToTextProperty(&window->popup.name,1,&window_name);
  5857.   XSetWMName(display,window->popup.id,&window_name);
  5858.   window_changes.width=window->popup.width;
  5859.   window_changes.height=window->popup.height;
  5860.   window_changes.x=window->popup.x;
  5861.   window_changes.y=window->popup.y;
  5862.   XReconfigureWMWindow(display,window->popup.id,window->popup.screen,CWWidth |
  5863.     CWHeight | CWX | CWY,&window_changes);
  5864.   XMapRaised(display,window->popup.id);
  5865.   /*
  5866.     Respond to X events.
  5867.   */
  5868.   XGetWidgetInfo((char *) NULL,&north_info);
  5869.   XGetWidgetInfo((char *) NULL,&south_info);
  5870.   visible_lines=0;
  5871.   delay=SuspendTime << 2;
  5872.   state=UpdateConfigurationState;
  5873.   do
  5874.   {
  5875.     /*
  5876.       Wait for next event.
  5877.     */
  5878.     if (north_info.raised && south_info.raised)
  5879.       XIfEvent(display,&event,XWidgetEvent,(char *) window);
  5880.     else
  5881.       {
  5882.         /*
  5883.           Brief delay before advancing scroll bar.
  5884.         */
  5885.         XDelay(display,delay);
  5886.         XCheckMaskEvent(display,ButtonReleaseMask,&event);
  5887.         delay=SuspendTime;
  5888.       }
  5889.     switch (event.type)
  5890.     {
  5891.       case ButtonPress:
  5892.       {
  5893.         if (event.xbutton.window != window->popup.id)
  5894.           {
  5895.             XBell(display,0);
  5896.             break;
  5897.           }
  5898.         if (MatteIsActive(slider_info,event.xbutton))
  5899.           {
  5900.             /*
  5901.               Track slider.
  5902.             */
  5903.             slider_info.active=True;
  5904.             break;
  5905.           }
  5906.         if (MatteIsActive(north_info,event.xbutton))
  5907.           if (slider_info.id > 0)
  5908.             {
  5909.               /*
  5910.                 Move slider up.
  5911.               */
  5912.               north_info.raised=False;
  5913.               slider_info.id--;
  5914.               state|=RedrawListState;
  5915.               break;
  5916.             }
  5917.         if (MatteIsActive(south_info,event.xbutton))
  5918.           if (slider_info.id < lines)
  5919.             {
  5920.               /*
  5921.                 Move slider down.
  5922.               */
  5923.               south_info.raised=False;
  5924.               slider_info.id++;
  5925.               state|=RedrawListState;
  5926.               break;
  5927.             }
  5928.         if (MatteIsActive(scroll_info,event.xbutton))
  5929.           {
  5930.             /*
  5931.               Move slider.
  5932.             */
  5933.             if (event.xbutton.y < slider_info.y)
  5934.               slider_info.id-=(visible_lines-1);
  5935.             else
  5936.               slider_info.id+=(visible_lines-1);
  5937.             state|=RedrawListState;
  5938.             break;
  5939.           }
  5940.         if (MatteIsActive(dismiss_info,event.xbutton))
  5941.           {
  5942.             /*
  5943.               User pressed Dismiss button.
  5944.             */
  5945.             dismiss_info.raised=False;
  5946.             XDrawBeveledButton(display,&window->popup,&dismiss_info);
  5947.             break;
  5948.           }
  5949.         if ((event.xbutton.button == Button3) &&
  5950.             (event.xbutton.state & Mod1Mask))
  5951.           {
  5952.             /*
  5953.               Convert Alt-Matte3 to Button2.
  5954.             */
  5955.             event.xbutton.button=Button2;
  5956.             event.xbutton.state&=(~Mod1Mask);
  5957.           }
  5958.         break;
  5959.       }
  5960.       case ButtonRelease:
  5961.       {
  5962.         if (!north_info.raised)
  5963.           {
  5964.             /*
  5965.               User released up button.
  5966.             */
  5967.             delay=SuspendTime << 2;
  5968.             north_info.raised=True;
  5969.             XDrawTriangleNorth(display,&window->popup,&north_info);
  5970.           }
  5971.         if (!south_info.raised)
  5972.           {
  5973.             /*
  5974.               User released down button.
  5975.             */
  5976.             delay=SuspendTime << 2;
  5977.             south_info.raised=True;
  5978.             XDrawTriangleSouth(display,&window->popup,&south_info);
  5979.           }
  5980.         if (slider_info.active)
  5981.           {
  5982.             /*
  5983.               Stop tracking slider.
  5984.             */
  5985.             slider_info.active=False;
  5986.             break;
  5987.           }
  5988.         if (!dismiss_info.raised)
  5989.           {
  5990.             if (event.xbutton.window == window->popup.id)
  5991.               if (MatteIsActive(dismiss_info,event.xbutton))
  5992.                 state|=ExitState;
  5993.             dismiss_info.raised=True;
  5994.             XDrawBeveledButton(display,&window->popup,&dismiss_info);
  5995.           }
  5996.         break;
  5997.       }
  5998.       case ConfigureNotify:
  5999.       {
  6000.         /*
  6001.           Update widget configuration.
  6002.         */
  6003.         if (event.xconfigure.window != window->popup.id)
  6004.           break;
  6005.         if ((window->popup.width != event.xconfigure.width) ||
  6006.             (window->popup.height != event.xconfigure.height))
  6007.           state|=RedrawWidgetState;
  6008.         window->popup.width=Max(event.xconfigure.width,window->popup.min_width);
  6009.         window->popup.height=
  6010.           Max(event.xconfigure.height,window->popup.min_height);
  6011.         state|=UpdateConfigurationState;
  6012.         break;
  6013.       }
  6014.       case Expose:
  6015.       {
  6016.         if (event.xexpose.window == window->image.id)
  6017.           {
  6018.             XRefreshWindow(display,&window->image,&event);
  6019.             break;
  6020.           }
  6021.         if (event.xexpose.window == window->magnify.id)
  6022.           if (event.xexpose.count == 0)
  6023.             if (window->magnify.mapped)
  6024.               {
  6025.                 XMakeMagnifyImage(display,resource_info,window);
  6026.                 break;
  6027.               }
  6028.         if (event.xexpose.window != window->popup.id)
  6029.           break;
  6030.         if (event.xexpose.count != 0)
  6031.           break;
  6032.         state|=RedrawWidgetState;
  6033.         break;
  6034.       }
  6035.       case KeyPress:
  6036.       {
  6037.         static char
  6038.           command[MaxTextLength];
  6039.  
  6040.         static int
  6041.           length;
  6042.  
  6043.         static KeySym
  6044.           key_symbol;
  6045.  
  6046.         if (event.xkey.window != window->popup.id)
  6047.           break;
  6048.         /*
  6049.           Respond to a user key press.
  6050.         */
  6051.         length=XLookupString((XKeyEvent *) &event.xkey,command,sizeof(command),
  6052.           &key_symbol,(XComposeStatus *) NULL);
  6053.         *(command+length)='\0';
  6054.         if (key_symbol == XK_Up)
  6055.           if (MatteIsActive(scroll_info,event.xkey))
  6056.             if (slider_info.id > 0)
  6057.               {
  6058.                 /*
  6059.                   Move slider up.
  6060.                 */
  6061.                 slider_info.id--;
  6062.                 state|=RedrawListState;
  6063.                 break;
  6064.               }
  6065.         if (key_symbol == XK_Down)
  6066.           if (MatteIsActive(scroll_info,event.xkey))
  6067.             if (slider_info.id < lines)
  6068.               {
  6069.                 /*
  6070.                   Move slider down.
  6071.                 */
  6072.                 slider_info.id++;
  6073.                 state|=RedrawListState;
  6074.                 break;
  6075.               }
  6076.         break;
  6077.       }
  6078.       case KeyRelease:
  6079.         break;
  6080.       case MotionNotify:
  6081.       {
  6082.         /*
  6083.           Discard pending button motion events.
  6084.         */
  6085.         while (XCheckMaskEvent(display,ButtonMotionMask,&event));
  6086.         if (event.xmotion.window == window->image.id)
  6087.           {
  6088.             XTranslateCoordinates(display,event.xmotion.window,window->popup.id,
  6089.               0,0,&x_offset,&y_offset,&child);
  6090.             event.xmotion.x+=x_offset;
  6091.             event.xmotion.y+=y_offset;
  6092.           }
  6093.         if (slider_info.active)
  6094.           {
  6095.             /*
  6096.               Move slider matte.
  6097.             */
  6098.             slider_info.y=event.xmotion.y-
  6099.               ((slider_info.height+slider_info.bevel_width) >> 1)+1;
  6100.             if (slider_info.y < slider_info.min_y)
  6101.               slider_info.y=slider_info.min_y;
  6102.             if (slider_info.y > slider_info.max_y)
  6103.               slider_info.y=slider_info.max_y;
  6104.             slider_info.id=(lines*(slider_info.y-slider_info.min_y+1))/
  6105.               (slider_info.max_y-slider_info.min_y+1);
  6106.             state|=RedrawListState;
  6107.             break;
  6108.           }
  6109.         if (dismiss_info.raised == MatteIsActive(dismiss_info,event.xmotion))
  6110.           {
  6111.             /*
  6112.               Dismiss button status changed.
  6113.             */
  6114.             dismiss_info.raised=!dismiss_info.raised;
  6115.             XDrawBeveledButton(display,&window->popup,&dismiss_info);
  6116.             break;
  6117.           }
  6118.         break;
  6119.       }
  6120.       default:
  6121.         break;
  6122.     }
  6123.     if (state & UpdateConfigurationState)
  6124.       {
  6125.         /*
  6126.           Initialize button information.
  6127.         */
  6128.         XGetWidgetInfo(DismissButtonText,&dismiss_info);
  6129.         dismiss_info.width=width;
  6130.         dismiss_info.height=(3*height) >> 1;
  6131.         dismiss_info.x=window->popup.width-dismiss_info.width-
  6132.           font_info->max_bounds.width-2;
  6133.         dismiss_info.y=window->popup.height-dismiss_info.height-
  6134.           font_info->max_bounds.width;
  6135.         /*
  6136.           Initialize scroll information.
  6137.         */
  6138.         XGetWidgetInfo((char *) NULL,&scroll_info);
  6139.         scroll_info.bevel_width--;
  6140.         scroll_info.width=height;
  6141.         scroll_info.height=dismiss_info.y-
  6142.           ((5*font_info->max_bounds.width) >> 1);
  6143.         scroll_info.x=window->popup.width-font_info->max_bounds.width-
  6144.           scroll_info.width;
  6145.         scroll_info.y=(3*font_info->max_bounds.width) >> 1;
  6146.         scroll_info.raised=False;
  6147.         scroll_info.trough=True;
  6148.         north_info=scroll_info;
  6149.         north_info.raised=True;
  6150.         north_info.width-=(north_info.bevel_width << 1);
  6151.         north_info.height=north_info.width-1;
  6152.         north_info.x+=north_info.bevel_width;
  6153.         north_info.y+=north_info.bevel_width;
  6154.         south_info=north_info;
  6155.         south_info.y=scroll_info.y+scroll_info.height-scroll_info.bevel_width-
  6156.           south_info.height;
  6157.         slider_info=north_info;
  6158.         slider_info.id=0;
  6159.         slider_info.width-=2;
  6160.         slider_info.min_y=north_info.y+north_info.height+north_info.bevel_width+
  6161.           slider_info.bevel_width+2;
  6162.         slider_info.height=
  6163.           scroll_info.height-((slider_info.min_y-scroll_info.y+1) << 1)+2;
  6164.         visible_lines=(scroll_info.height-(height >> 3)-4)/((9*height) >> 3);
  6165.         if (lines > visible_lines)
  6166.           slider_info.height=(visible_lines*slider_info.height)/lines;
  6167.         slider_info.max_y=south_info.y-south_info.bevel_width-
  6168.           slider_info.height-slider_info.bevel_width;
  6169.         slider_info.x=scroll_info.x+slider_info.bevel_width+1;
  6170.         slider_info.y=slider_info.min_y;
  6171.         expose_info=scroll_info;
  6172.         expose_info.y=slider_info.y;
  6173.         /*
  6174.           Initialize list information.
  6175.         */
  6176.         XGetWidgetInfo((char *) NULL,&list_info);
  6177.         list_info.raised=False;
  6178.         list_info.bevel_width--;
  6179.         list_info.width=scroll_info.x-((3*font_info->max_bounds.width) >> 1);
  6180.         list_info.height=scroll_info.height;
  6181.         list_info.x=font_info->max_bounds.width;
  6182.         list_info.y=scroll_info.y;
  6183.         /*
  6184.           Initialize selection information.
  6185.         */
  6186.         XGetWidgetInfo((char *) NULL,&selection_info);
  6187.         selection_info.width=list_info.width;
  6188.         selection_info.height=(9*height) >> 3;
  6189.         selection_info.x=list_info.x;
  6190.         state&=(~UpdateConfigurationState);
  6191.       }
  6192.     if (state & RedrawWidgetState)
  6193.       {
  6194.         /*
  6195.           Redraw file browser window.
  6196.         */
  6197.         XClearWindow(display,window->popup.id);
  6198.         XDrawBeveledMatte(display,&window->popup,&list_info);
  6199.         XDrawBeveledMatte(display,&window->popup,&scroll_info);
  6200.         XDrawTriangleNorth(display,&window->popup,&north_info);
  6201.         XDrawBeveledButton(display,&window->popup,&slider_info);
  6202.         XDrawTriangleSouth(display,&window->popup,&south_info);
  6203.         XDrawBeveledButton(display,&window->popup,&dismiss_info);
  6204.         XHighlightWidget(display,&window->popup,4,4);
  6205.         selection_info.id=(~0);
  6206.         state|=RedrawListState;
  6207.         state&=(~RedrawWidgetState);
  6208.       }
  6209.     if (state & RedrawListState)
  6210.       {
  6211.         /*
  6212.           Determine slider id and position.
  6213.         */
  6214.         if (slider_info.id >= lines)
  6215.           slider_info.id=lines-1;
  6216.         if ((slider_info.id < 0) || (lines <= visible_lines))
  6217.           slider_info.id=0;
  6218.         slider_info.y=slider_info.min_y;
  6219.         if (lines != 0)
  6220.           slider_info.y+=
  6221.             slider_info.id*(slider_info.max_y-slider_info.min_y+1)/lines;
  6222.         if (slider_info.id != selection_info.id)
  6223.           {
  6224.             /*
  6225.               Redraw scroll bar and file names.
  6226.             */
  6227.             selection_info.id=slider_info.id;
  6228.             selection_info.y=list_info.y+(height >> 3)+2;
  6229.             for (i=0; i < visible_lines; i++)
  6230.             {
  6231.               selection_info.raised=(slider_info.id+i) != list_info.id;
  6232.               selection_info.text=(char *) NULL;
  6233.               if ((slider_info.id+i) < lines)
  6234.                 selection_info.text=textlist[slider_info.id+i];
  6235.               XDrawWidgetText(display,&window->popup,&selection_info);
  6236.               selection_info.y+=(int) selection_info.height;
  6237.             }
  6238.             /*
  6239.               Update slider.
  6240.             */
  6241.             if (slider_info.y > expose_info.y)
  6242.               {
  6243.                 expose_info.height=slider_info.y-expose_info.y;
  6244.                 expose_info.y=slider_info.y-expose_info.height-
  6245.                   slider_info.bevel_width-1;
  6246.               }
  6247.             else
  6248.               {
  6249.                 expose_info.height=expose_info.y-slider_info.y;
  6250.                 expose_info.y=slider_info.y+slider_info.height+
  6251.                   slider_info.bevel_width+1;
  6252.               }
  6253.             XDrawTriangleNorth(display,&window->popup,&north_info);
  6254.             XDrawMatte(display,&window->popup,&expose_info);
  6255.             XDrawBeveledButton(display,&window->popup,&slider_info);
  6256.             XDrawTriangleSouth(display,&window->popup,&south_info);
  6257.             expose_info.y=slider_info.y;
  6258.           }
  6259.         state&=(~RedrawListState);
  6260.       }
  6261.   } while (!(state & ExitState));
  6262.   XDefineCursor(display,window->image.id,window->image.cursor);
  6263.   XWithdrawWindow(display,window->popup.id,window->popup.screen);
  6264.   XDelay(display,SuspendTime << 2);
  6265.   while (XCheckTypedWindowEvent(display,window->image.id,Expose,&event))
  6266.     XRefreshWindow(display,&window->image,&event);
  6267. }
  6268.